
    ei              
       n   d dl mZmZ d dlmZmZmZmZmZm	Z	m
Z
 d dlZd dlmZ d dlmZmZmZmZmZmZmZmZmZmZ d dlmZmZmZ e G d d             Ze G d	 d
             Ze G d de             Z e G d de             Z!e G d de             Z"e G d de             Z#e G d de             Z$e G d de             Z%e G d de             Z&e G d de             Z'e G d de             Z(e G d de             Z)e G d d e             Z*e G d! d"e             Z+e G d# d$e             Z,e G d% d&e             Z- G d' d(      Z. e.d)      e._/         e.d*      e._0         e.d+      e._1         e.d,      e._2         e.d-      e._3        e.Z4e G d. d/             Z5e G d0 d1             Z6e G d2 d3             Z7e G d4 d5             Z8e G d6 d7             Z9e G d8 d9e9             Z:e G d: d;e9             Z;e G d< d=e9             Z<e G d> d?e9             Z=e G d@ dAe9             Z>e G dB dCe9             Z?e G dD dEe9             Z@e G dF dGe9             ZAe G dH dIe9             ZBe G dJ dKe9             ZCe G dL dMe9             ZDe G dN dOe9             ZEe G dP dQ             ZFdRee	e.eGf      dSeeG   fdTZHdRe	ee   eIedUf   f   dSee	e.eGf      fdVZJdWeGdXeeGef   dSeIee	e.eGf      eKf   fdYZLe G dZ d[             ZMe G d\ d]eM             ZNe G d^ d_eM             ZOe G d` da             ZPy)b    )	dataclassfield)OptionalListDictSetAnyUnioncastN)NDArray)

EmbeddingsIDsInclude	OneOrManySparseVectorTYPE_KEYSPARSE_VECTOR_TYPE_VALUEmaybe_cast_one_to_manynormalize_embeddingsvalidate_embeddings)
CollectionRequestVersionContextSegmentc                   L    e Zd ZU eed<   eed<   eed<   eed<   edefd       Zy)Scan
collectionknnmetadatarecordreturnc                 l    t        | j                  j                  | j                  j                        S )N)collection_versionlog_position)r   r   versionr#   selfs    p/home/obispo/Crisostomo_bridge/mision_env/lib/python3.12/site-packages/chromadb/execution/expression/operator.pyr$   zScan.version    s)    $#6655
 	
    N)	__name__
__module____qualname__r   __annotations__r   propertyr   r$    r(   r'   r   r      s2    	LO
. 
 
r(   r   c                   Z    e Zd ZdZdeeef   fdZedeeef   dd fd       Z	d	dZ
d
dZy)Wherea?  Base class for Where expressions (algebraic data type).

    Supports logical operators for combining conditions:
        - AND: where1 & where2
        - OR: where1 | where2

    Examples:
        # Simple conditions
        where1 = Key("status") == "active"
        where2 = Key("score") > 0.5

        # Combining with AND
        combined_and = where1 & where2

        # Combining with OR
        combined_or = where1 | where2

        # Complex expressions
        complex_where = (Key("status") == "active") & ((Key("score") > 0.5) | (Key("priority") == "high"))
    r    c                     t        d      )zCConvert the Where expression to a dictionary for JSON serialization#Subclasses must implement to_dict()NotImplementedErrorr%   s    r'   to_dictzWhere.to_dict@       !"GHHr(   datac                 $
   t        | t              s!t        dt        |       j                         | st        d      d| v rt        | d   t              s$t        dt        | d         j                         t        | d         dk(  rt        d      t        |       dkD  rt        d      | d   D cg c]  }t        j                  |       }}t        |      dk(  r|d   S |d   }|dd	 D ]  }||z  }	 |S d
| v rt        | d
   t              s$t        dt        | d
         j                         t        | d
         dk(  rt        d      t        |       dkD  rt        d      | d
   D cg c]  }t        j                  |       }}t        |      dk(  r|d   S |d   }|dd	 D ]  }||z  }	 |S t        |       dk7  rt        dt        |              t        t        | j                                     \  }}t        |t              s!t        dt        |      j                         t        |t              r|st        d| d      t        |      dk7  rt        d| d      t        t        |j                                     \  }}|dk(  rt        |      |k(  S |dk(  rt        |      |k7  S |dk(  rt        |      |kD  S |dk(  rt        |      |k\  S |dk(  rt        |      |k  S |dk(  rt        |      |k  S |dk(  rKt        |t              s!t        dt        |      j                         t        |      j                  |      S |dk(  rKt        |t              s!t        dt        |      j                         t        |      j!                  |      S |dk(  rKt        |t              s!t        dt        |      j                         t        |      j#                  |      S |dk(  rKt        |t              s!t        d t        |      j                         t        |      j%                  |      S |d!k(  rKt        |t              s!t        d"t        |      j                         t        |      j'                  |      S |d#k(  rKt        |t              s!t        d$t        |      j                         t        |      j)                  |      S t        d%|       t        |      |k(  S c c}w c c}w )&at  Create Where expression from dictionary.

        Supports MongoDB-style query operators:
        - {"field": "value"} -> Key("field") == "value" (shorthand for equality)
        - {"field": {"$eq": value}} -> Key("field") == value
        - {"field": {"$ne": value}} -> Key("field") != value
        - {"field": {"$gt": value}} -> Key("field") > value
        - {"field": {"$gte": value}} -> Key("field") >= value
        - {"field": {"$lt": value}} -> Key("field") < value
        - {"field": {"$lte": value}} -> Key("field") <= value
        - {"field": {"$in": [values]}} -> Key("field").is_in([values])
        - {"field": {"$nin": [values]}} -> Key("field").not_in([values])
        - {"field": {"$contains": "text"}} -> Key("field").contains("text")
        - {"field": {"$not_contains": "text"}} -> Key("field").not_contains("text")
        - {"field": {"$regex": "pattern"}} -> Key("field").regex("pattern")
        - {"field": {"$not_regex": "pattern"}} -> Key("field").not_regex("pattern")
        - {"$and": [conditions]} -> condition1 & condition2 & ...
        - {"$or": [conditions]} -> condition1 | condition2 | ...
        zExpected dict for Where, got zWhere dict cannot be empty$andz$and must be a list, got r   z$$and requires at least one condition   z:$and cannot be combined with other fields in the same dictN$orz$or must be a list, got z#$or requires at least one conditionz9$or cannot be combined with other fields in the same dictz/Where dict must contain exactly one field, got z!Field name must be a string, got zOperator dict for field 'z' cannot be emptyz#' must contain exactly one operator$eq$ne$gt$gte$lt$lte$inz$in requires a list, got $ninz$nin requires a list, got 	$containsz!$contains requires a string, got $not_containsz%$not_contains requires a string, got $regexz&$regex requires a string pattern, got 
$not_regexz*$not_regex requires a string pattern, got zUnknown operator: )
isinstancedict	TypeErrortyper)   
ValueErrorlistlenr0   	from_dictnextiteritemsstrKeyis_innot_incontainsnot_containsregex	not_regex)r7   c
conditionsresultr   	conditionopvalues           r'   rO   zWhere.from_dictD   s<   * $%;DJ<O<O;PQRR9:: T>d6lD1/T&\0B0K0K/LM  4< A% !GHH4y1} P  7;6lC%//!,CJC:!#!!}$]F^ $!$Md]d5k40":4U;L;U;U:V WXX4;1$ !FGG4y1} O  7;5kB%//!,BJB:!#!!}$]F^ $!$M 4yA~ Ec$i[Q   $D$67E9eS)7U8L8L7MN  )T* $3E7:KL  y>Q&$3E7:]^  !ioo&7!89	E;u:..5[u:..5[u:--6\u:..5[u:--6\u:..5[%eT2'7U8L8L7MN  u:++E226\%eT2'8e9M9M8NO  u:,,U33;&%eS1'?U@T@T?UV  u:..u55?*%eS1'CDKDXDXCYZ  u:225998^%eS1'DT%[EYEYDZ[  u:++E22<'%eS1'HeI]I]H^_  u://66$'9"%>?? 5zY..S D$ Cs   6T4Tc                 $   t        | t              rKt        |t              r"t        | j                  |j                  z         S t        | j                  |gz         S t        |t              rt        | g|j                  z         S t        | |g      S )zOverload & operator for AND)rH   Andr\   r&   others     r'   __and__zWhere.__and__   sy     dC %%4??U-=-==>>t%011s#v 0 0011D%=!!r(   c                 $   t        | t              rKt        |t              r"t        | j                  |j                  z         S t        | j                  |gz         S t        |t              rt        | g|j                  z         S t        | |g      S )zOverload | operator for OR)rH   Orr\   rc   s     r'   __or__zWhere.__or__   sy     dB%$$//E,<,<<==doo/00r"tfu///004-  r(   N)rd   r0   r    rb   )rd   r0   r    rg   )r)   r*   r+   __doc__r   rS   r	   r5   staticmethodrO   re   rh   r.   r(   r'   r0   r0   )   sV    *Ic3h I P/S#X P/7 P/ P/d"!r(   r0   c                   8    e Zd ZU dZee   ed<   deee	f   fdZ
y)rb   z(Logical AND of multiple where conditionsr\   r    c                 `    d| j                   D cg c]  }|j                          c}iS c c}w )Nr9   r\   r5   r&   r[   s     r'   r5   zAnd.to_dict   s%    doo>>??>   +Nr)   r*   r+   ri   r   r0   r,   r   rS   r	   r5   r.   r(   r'   rb   rb      s%    2U@c3h @r(   rb   c                   8    e Zd ZU dZee   ed<   deee	f   fdZ
y)rg   z'Logical OR of multiple where conditionsr\   r    c                 `    d| j                   D cg c]  }|j                          c}iS c c}w )Nr;   rm   rn   s     r'   r5   z
Or.to_dict  s%    T__=		=>>=ro   Nrp   r.   r(   r'   rg   rg      s#    1U?c3h ?r(   rg   c                   <    e Zd ZU dZeed<   eed<   deeef   fdZy)EqzEquality comparisonkeyr`   r    c                 6    | j                   d| j                  iiS )Nr<   ru   r`   r%   s    r'   r5   z
Eq.to_dict      5$**-..r(   N	r)   r*   r+   ri   rS   r,   r	   r   r5   r.   r(   r'   rt   rt     s#    	HJ/c3h /r(   rt   c                   <    e Zd ZU dZeed<   eed<   deeef   fdZy)NezNot equal comparisonru   r`   r    c                 6    | j                   d| j                  iiS )Nr=   rw   r%   s    r'   r5   z
Ne.to_dict  rx   r(   Nry   r.   r(   r'   r{   r{     #    	HJ/c3h /r(   r{   c                   <    e Zd ZU dZeed<   eed<   deeef   fdZy)GtzGreater than comparisonru   r`   r    c                 6    | j                   d| j                  iiS )Nr>   rw   r%   s    r'   r5   z
Gt.to_dict%  rx   r(   Nry   r.   r(   r'   r   r     s#    !	HJ/c3h /r(   r   c                   <    e Zd ZU dZeed<   eed<   deeef   fdZy)Gtez Greater than or equal comparisonru   r`   r    c                 6    | j                   d| j                  iiS )Nr?   rw   r%   s    r'   r5   zGte.to_dict0      64::.//r(   Nry   r.   r(   r'   r   r   )  s#    *	HJ0c3h 0r(   r   c                   <    e Zd ZU dZeed<   eed<   deeef   fdZy)LtzLess than comparisonru   r`   r    c                 6    | j                   d| j                  iiS )Nr@   rw   r%   s    r'   r5   z
Lt.to_dict;  rx   r(   Nry   r.   r(   r'   r   r   4  r}   r(   r   c                   <    e Zd ZU dZeed<   eed<   deeef   fdZy)LtezLess than or equal comparisonru   r`   r    c                 6    | j                   d| j                  iiS )NrA   rw   r%   s    r'   r5   zLte.to_dictF  r   r(   Nry   r.   r(   r'   r   r   ?  s#    '	HJ0c3h 0r(   r   c                   B    e Zd ZU dZeed<   ee   ed<   deeef   fdZ	y)Inz"In comparison - value is in a listru   valuesr    c                 6    | j                   d| j                  iiS )NrB   ru   r   r%   s    r'   r5   z
In.to_dictQ  s    5$++.//r(   N
r)   r*   r+   ri   rS   r,   r   r	   r   r5   r.   r(   r'   r   r   J  s(    ,	HI0c3h 0r(   r   c                   B    e Zd ZU dZeed<   ee   ed<   deeef   fdZ	y)Ninz*Not in comparison - value is not in a listru   r   r    c                 6    | j                   d| j                  iiS )NrC   r   r%   s    r'   r5   zNin.to_dict\  s    64;;/00r(   Nr   r.   r(   r'   r   r   U  s(    4	HI1c3h 1r(   r   c                   <    e Zd ZU dZeed<   eed<   deeef   fdZy)Containsz(Contains comparison for document contentru   contentr    c                 6    | j                   d| j                  iiS )NrD   ru   r   r%   s    r'   r5   zContains.to_dictg  s    ;566r(   N	r)   r*   r+   ri   rS   r,   r   r	   r5   r.   r(   r'   r   r   `  s#    2	HL7c3h 7r(   r   c                   <    e Zd ZU dZeed<   eed<   deeef   fdZy)NotContainsz,Not contains comparison for document contentru   r   r    c                 6    | j                   d| j                  iiS )NrE   r   r%   s    r'   r5   zNotContains.to_dictr  s    ?DLL9::r(   Nr   r.   r(   r'   r   r   k  s#    6	HL;c3h ;r(   r   c                   <    e Zd ZU dZeed<   eed<   deeef   fdZy)RegexzRegular expression matchingru   patternr    c                 6    | j                   d| j                  iiS )NrF   ru   r   r%   s    r'   r5   zRegex.to_dict}  s    8T\\233r(   Nr   r.   r(   r'   r   r   v  s#    %	HL4c3h 4r(   r   c                   <    e Zd ZU dZeed<   eed<   deeef   fdZy)NotRegexz$Negative regular expression matchingru   r   r    c                 6    | j                   d| j                  iiS )NrG   r   r%   s    r'   r5   zNotRegex.to_dict  s    <677r(   Nr   r.   r(   r'   r   r     s#    .	HL8c3h 8r(   r   c                   (   e Zd ZU dZd ed<   d ed<   d ed<   d ed<   d ed<   defdZd	efd
Zde	d	e
fdZde	d	efdZde	d	efdZde	d	efdZde	d	efdZde	d	efdZdee	   d	efdZdee	   d	efdZded	efdZded	efdZded	efdZ ded	e!fdZ"y)rT   a  Field proxy for building Where conditions with operator overloading.

    The Key class allows for readable field references using either:
    1. Predefined constants for special fields: K.EMBEDDING, K.DOCUMENT, K.SCORE, etc.
    2. String literals with # prefix for special fields: Key("#embedding")
    3. Metadata field names without # prefix: Key("my_metadata_field")

    Predefined field constants (special fields with # prefix):
        Key.ID - ID field (equivalent to Key("#id"))
        Key.DOCUMENT - Document field (equivalent to Key("#document"))
        Key.EMBEDDING - Embedding field (equivalent to Key("#embedding"))
        Key.METADATA - Metadata field (equivalent to Key("#metadata"))
        Key.SCORE - Score field (equivalent to Key("#score"))

    Note: K is an alias for Key, so you can use K.DOCUMENT or Key.DOCUMENT interchangeably.

    Examples:
        # Using predefined keys with K alias for special fields
        from chromadb.execution.expression import K
        K.DOCUMENT.contains("search text")  # Searches document field

        # Custom metadata field names (without # prefix)
        K("status") == "active"  # Metadata field named "status"
        K("category").is_in(["science", "tech"])  # Metadata field named "category"
        K("sparse_embedding")  # Example: metadata field (could store anything)

        # Using with Knn for different fields
        Knn(query=[0.1, 0.2])  # Default: searches "#embedding"
        Knn(query=[0.1, 0.2], key=K.EMBEDDING)  # Explicit: searches "#embedding"
        Knn(query=sparse, key="sparse_embedding")  # Example: searches a metadata field

        # Combining conditions
        (K("status") == "active") & (K.SCORE > 0.5)
    IDDOCUMENT	EMBEDDINGMETADATASCOREnamec                     || _         y )N)r   )r&   r   s     r'   __init__zKey.__init__  s	    	r(   r    c                 ,    t        | j                        S )z!Make Key hashable for use in sets)hashr   r%   s    r'   __hash__zKey.__hash__  s    DIIr(   r`   c                 .    t        | j                  |      S )zEquality: Key('field') == value)rt   r   r&   r`   s     r'   __eq__z
Key.__eq__      $))U##r(   c                 .    t        | j                  |      S )z Not equal: Key('field') != value)r{   r   r   s     r'   __ne__z
Key.__ne__  r   r(   c                 .    t        | j                  |      S )z"Greater than: Key('field') > value)r   r   r   s     r'   __gt__z
Key.__gt__  r   r(   c                 .    t        | j                  |      S )z,Greater than or equal: Key('field') >= value)r   r   r   s     r'   __ge__z
Key.__ge__      499e$$r(   c                 .    t        | j                  |      S )zLess than: Key('field') < value)r   r   r   s     r'   __lt__z
Key.__lt__  r   r(   c                 .    t        | j                  |      S )z)Less than or equal: Key('field') <= value)r   r   r   s     r'   __le__z
Key.__le__  r   r(   r   c                 .    t        | j                  |      S )z?Check if field value is in list: Key('field').is_in(['a', 'b']))r   r   r&   r   s     r'   rU   z	Key.is_in  s    $))V$$r(   c                 .    t        | j                  |      S )zDCheck if field value is not in list: Key('field').not_in(['a', 'b']))r   r   r   s     r'   rV   z
Key.not_in  s    499f%%r(   r   c                 .    t        | j                  |      S )z9Match field against regex: Key('field').regex('^pattern'))r   r   r&   r   s     r'   rY   z	Key.regex  s    TYY((r(   c                 .    t        | j                  |      S )z@Field should not match regex: Key('field').not_regex('^pattern'))r   r   r   s     r'   rZ   zKey.not_regex      		7++r(   r   c                 .    t        | j                  |      S )z;Check if field contains text: Key('field').contains('text'))r   r   r&   r   s     r'   rW   zKey.contains  r   r(   c                 .    t        | j                  |      S )zFCheck if field doesn't contain text: Key('field').not_contains('text'))r   r   r   s     r'   rX   zKey.not_contains  s    499g..r(   N)#r)   r*   r+   ri   r,   rS   r   intr   r	   rt   r   r{   r   r   r   r   r   r   r   r   r   r   r   rU   r   rV   r   rY   r   rZ   r   rW   r   rX   r.   r(   r'   rT   rT     s(   !H 	IOOLS # 
$C $B $$C $B $$C $B $%C %C %$C $B $%C %C %
%DI %" %&T#Y &3 &)S )U ), , ,, , ,/C /K /r(   rT   #id	#document
#embedding	#metadata#scorec                   J    e Zd ZU dZee   ed<   dZee   ed<   dZ	ee   ed<   y)FilterNuser_idswherewhere_document)
r)   r*   r+   r   r   r   r,   r   r	   r   r.   r(   r'   r   r     s,    "Hhsm"E8C=$(NHSM(r(   r   c                   "    e Zd ZU eed<   eed<   y)KNN
embeddingsfetchN)r)   r*   r+   r   r,   r   r.   r(   r'   r   r     s    Jr(   r   c                   j    e Zd ZU dZeed<   dZee   ed<   dee	e
f   fdZedee	e
f   dd fd       Zy)	Limitr   offsetNlimitr    c                 X    d| j                   i}| j                  | j                  |d<   |S )z8Convert the Limit to a dictionary for JSON serializationr   r   r   r   r&   r]   s     r'   r5   zLimit.to_dict  s,    DKK(::!"jjF7Or(   r7   c                 8   t        | t              s!t        dt        |       j                         | j                  dd      }t        |t              s!t        dt        |      j                         |dk  rt        d|       | j                  d      }|Dt        |t              s!t        dt        |      j                         |dk  rt        d|       ddh}t        | j                               |z
  }|rt        d	|       t        ||
      S )zCreate Limit from dictionary.

        Examples:
        - {"offset": 10} -> Limit(offset=10)
        - {"offset": 10, "limit": 20} -> Limit(offset=10, limit=20)
        - {"limit": 20} -> Limit(offset=0, limit=20)
        zExpected dict for Limit, got r   r   z%Limit offset must be an integer, got z'Limit offset must be non-negative, got r   z$Limit limit must be an integer, got z"Limit limit must be positive, got zUnexpected keys in Limit dict: r   )rH   rI   rJ   rK   r)   getr   rL   setkeysr   )r7   r   r   allowed_keysunexpected_keyss        r'   rO   zLimit.from_dict  s%    $%;DJ<O<O;PQRR(A&&#&7V8M8M7NO  A:FvhOPP!eS):4;;O;O:PQ  z #EeW!MNN !'*diik*\9>>OPQQF%00r(   )r)   r*   r+   r   r   r,   r   r   r   rS   r	   r5   rj   rO   r.   r(   r'   r   r   
  sW    FCOE8C=c3h  "1S#X "17 "1 "1r(   r   c                   j    e Zd ZU dZeed<   dZeed<   dZeed<   dZeed<   dZ	eed<   e
defd       Zy	)

ProjectionFdocument	embeddingr   rankurir    c                 <   t               }| j                  r|j                  d       | j                  r|j                  d       | j                  r|j                  d       | j
                  r|j                  d       | j                  r|j                  d       |S )N	documentsr   	metadatas	distancesuris)rM   r   appendr   r   r   r   )r&   includess     r'   includedzProjection.includedD  sm    6==OOK(>>OOL)==OOK(99OOK(88OOF#r(   N)r)   r*   r+   r   boolr,   r   r   r   r   r-   r   r   r.   r(   r'   r   r   <  sM    HdItHdD$C'  r(   r   c                      e Zd ZdZdeeef   fdZedeeef   dd fd       Z	de
d eef   ddfdZde
eef   ddfd	Zde
d eef   dd
fdZde
eef   dd
fdZde
d eef   ddfdZde
eef   ddfdZde
d eef   ddfdZde
eef   ddfdZddZddZddZddZd dZde
d eef   ddfdZde
d eef   ddfdZy)!Ranka  Base class for Rank expressions (algebraic data type).

    Supports arithmetic operations for combining rank expressions:
        - Addition: rank1 + rank2, rank + 0.5
        - Subtraction: rank1 - rank2, rank - 0.5
        - Multiplication: rank1 * rank2, rank * 0.8
        - Division: rank1 / rank2, rank / 2.0
        - Negation: -rank
        - Absolute value: abs(rank)

    Supports mathematical functions:
        - Exponential: rank.exp()
        - Logarithm: rank.log()
        - Maximum: rank.max(other)
        - Minimum: rank.min(other)

    Examples:
        # Weighted combination
        Knn(query=[0.1, 0.2]) * 0.8 + Val(0.5) * 0.2

        # Normalization
        Knn(query=[0.1, 0.2]) / Val(10.0)

        # Clamping
        Knn(query=[0.1, 0.2]).min(1.0).max(0.0)
    r    c                     t        d      )zCConvert the Score expression to a dictionary for JSON serializationr2   r3   r%   s    r'   r5   zRank.to_dictr  r6   r(   r7   c                    t        | t              s!t        dt        |       j                         | st        d      t        |       dk7  rt        dt        |              t        t        | j                                     }|dk(  rG| d   }t        |t        t        f      s!t        dt        |      j                         t        |      S |dk(  r | d   }t        |t              s!t        dt        |      j                         d	|vrt        d
      |d	   }t        |t              rN|j                  t              t        k(  rt!        j"                  |      }nt        dt         dt         d|       t        |t$        t&        t(        j*                  f      r7t-        |      }|rt        |      dkD  rt        d      t/        |       |d   }n!t        dt        |      j                         |j                  dd      }t        |t0              s!t        dt        |      j                         |j                  dd      }t        |t              s!t        dt        |      j                         |dk  rt        d|       |j                  dd      }t        |t2              s!t        dt        |      j                         t5        ||||j                  d      |      S |dk(  r| d   }	t        |	t$        t&        f      s!t        dt        |	      j                         t        |	      dk  rt        d t        |	             |	D 
cg c]  }
t6        j#                  |
       }}
|d   }|dd! D ]  }
||
z   }	 |S |d"k(  r~| d"   }t        |t              s!t        d#t        |      j                         d$|vsd%|vrt        d&      t6        j#                  |d$         }t6        j#                  |d%         }||z
  S |d'k(  r| d'   }	t        |	t$        t&        f      s!t        d(t        |	      j                         t        |	      dk  rt        d)t        |	             |	D 
cg c]  }
t6        j#                  |
       }}
|d   }|dd! D ]  }
||
z  }	 |S |d*k(  r~| d*   }t        |t              s!t        d+t        |      j                         d$|vsd%|vrt        d,      t6        j#                  |d$         }t6        j#                  |d%         }||z  S |d-k(  rT| d-   }t        |t              s!t        d.t        |      j                         t9        t6        j#                  |            S |d/k(  rY| d/   }t        |t              s!t        d0t        |      j                         t6        j#                  |      j;                         S |d1k(  rY| d1   }t        |t              s!t        d2t        |      j                         t6        j#                  |      j=                         S |d3k(  r| d3   }	t        |	t$        t&        f      s!t        d4t        |	      j                         t        |	      dk  rt        d5t        |	             |	D 
cg c]  }
t6        j#                  |
       }}
|d   }|dd! D ]  }
|j?                  |
      } |S |d6k(  r| d6   }	t        |	t$        t&        f      s!t        d7t        |	      j                         t        |	      dk  rt        d8t        |	             |	D 
cg c]  }
t6        j#                  |
       }}
|d   }|dd! D ]  }
|jA                  |
      } |S t        d9|       c c}
w c c}
w c c}
w c c}
w ):as  Create Rank expression from dictionary.

        Supports operators:
        - {"$val": number} -> Val(number)
        - {"$knn": {...}} -> Knn(...)
        - {"$sum": [ranks]} -> rank1 + rank2 + ...
        - {"$sub": {"left": ..., "right": ...}} -> left - right
        - {"$mul": [ranks]} -> rank1 * rank2 * ...
        - {"$div": {"left": ..., "right": ...}} -> left / right
        - {"$abs": rank} -> abs(rank)
        - {"$exp": rank} -> rank.exp()
        - {"$log": rank} -> rank.log()
        - {"$max": [ranks]} -> rank1.max(rank2).max(rank3)...
        - {"$min": [ranks]} -> rank1.min(rank2).min(rank3)...
        zExpected dict for Rank, got zRank dict cannot be emptyr:   z1Rank dict must contain exactly one operator, got $valz$val requires a number, got $knnz$knn requires a dict, got queryz$knn requires 'query' fieldzExpected dict with z='z', got z)$knn requires exactly one query embeddingr   zB$knn query must be a list, numpy array, or SparseVector dict, got ru   r   z$knn key must be a string, got r      z#$knn limit must be an integer, got z!$knn limit must be positive, got return_rankFz($knn return_rank must be a boolean, got default)r   ru   r   r   r   $sumz$sum requires a list, got    z$$sum requires at least 2 ranks, got N$subz2$sub requires a dict with 'left' and 'right', got leftrightz'$sub requires 'left' and 'right' fields$mulz$mul requires a list, got z$$mul requires at least 2 ranks, got $divz2$div requires a dict with 'left' and 'right', got z'$div requires 'left' and 'right' fields$absz$abs requires a rank dict, got $expz$exp requires a rank dict, got $logz$log requires a rank dict, got $maxz$max requires a list, got z$$max requires at least 2 ranks, got $minz$min requires a list, got z$$min requires at least 2 ranks, got zUnknown rank operator: )!rH   rI   rJ   rK   r)   rL   rN   rP   rQ   r   r   floatValr   r   r   r   rO   rM   tuplenpndarrayr   r   rS   r   Knnr   absexplogmaxmin)r7   r_   r`   knn_datar   
normalizedru   r   r   
ranks_datarranksr]   sub_datar  r  div_data
child_datas                     r'   rO   zRank.from_dictv  s   " $%:4:;N;N:OPQQ899t9>CCI;O  $tyy{#$<LEec5\2">tE{?S?S>T UVVu:6\F|Hh-"<T(^=T=T<U VWWh& !>??W%E%&99X&*BB(2259E %-hZr:R9SSZ[`Zab  ED%#<=1%8
!S_q%8$%PQQ $J/"1  XY]^cYdYmYmXno  ,,ul3Cc3'"A$s)BTBTAU VWWLL"-EeS)9$u+:N:N9OP  z #DUG!LMM",,}e<Kk40>tK?P?Y?Y>Z[   Y/'  6\fJj4-80j1A1J1J0KL  :" :3z?:KL  1;;1T^^A&;E;1XF12Y $!$M6\F|Hh-HhI`I`Hab  X%)@ !JKK>>(6"23DNN8G#45E%<6\fJj4-80j1A1J1J0KL  :" :3z?:KL  1;;1T^^A&;E;1XF12Y $!$M6\F|Hh-HhI`I`Hab  X%)@ !JKK>>(6"23DNN8G#45E%<6\fJj$/5d:6F6O6O5PQ  t~~j1226\fJj$/5d:6F6O6O5PQ  >>*-11336\fJj$/5d:6F6O6O5PQ  >>*-11336\fJj4-80j1A1J1J0KL  :" :3z?:KL  1;;1T^^A&;E;1XF12Y 'A'M6\fJj4-80j1A1J1J0KL  :" :3z?:KL  1;;1T^^A&;E;1XF12Y 'A'M 6rd;<<Y << <l <" <s   "^1^69^;#_ rd   Sumc                 j   t        |t        t        f      rt        |      n|}t        | t              rKt        |t              r"t	        | j
                  |j
                  z         S t	        | j
                  |gz         S t        |t              rt	        | g|j
                  z         S t	        | |g      S )z'Addition: rank1 + rank2 or rank + value)rH   r   r  r  r  r  r&   rd   
other_ranks      r'   __add__zRank.__add__R      #-ec5\#BSZ
dC *c*4::
(8(8899tzzZL011
C(v
 0 0011D*%&&r(   c                     t        |      | z   S )zRight addition: value + rankr  rc   s     r'   __radd__zRank.__radd__^      5zD  r(   Subc                 `    t        |t        t        f      rt        |      n|}t	        | |      S )z*Subtraction: rank1 - rank2 or rank - value)rH   r   r  r  r(  r   s      r'   __sub__zRank.__sub__b  '    #-ec5\#BSZ
4$$r(   c                 ,    t        t        |      |       S )zRight subtraction: value - rank)r(  r  rc   s     r'   __rsub__zRank.__rsub__g      3u:t$$r(   Mulc                 j   t        |t        t        f      rt        |      n|}t        | t              rKt        |t              r"t	        | j
                  |j
                  z         S t	        | j
                  |gz         S t        |t              rt	        | g|j
                  z         S t	        | |g      S )z-Multiplication: rank1 * rank2 or rank * value)rH   r   r  r  r/  r  r   s      r'   __mul__zRank.__mul__k  r#  r(   c                     t        |      | z  S )z"Right multiplication: value * rankr%  rc   s     r'   __rmul__zRank.__rmul__w  r'  r(   Divc                 `    t        |t        t        f      rt        |      n|}t	        | |      S )z'Division: rank1 / rank2 or rank / value)rH   r   r  r  r4  r   s      r'   __truediv__zRank.__truediv__{  r+  r(   c                 ,    t        t        |      |       S )zRight division: value / rank)r4  r  rc   s     r'   __rtruediv__zRank.__rtruediv__  r.  r(   c                 .    t        t        d      | g      S )z)Negation: -rank (equivalent to -1 * rank))r/  r  r%   s    r'   __neg__zRank.__neg__  s    CGT?##r(   c                     t        |       S )zAbsolute value: abs(rank)Absr%   s    r'   __abs__zRank.__abs__      4yr(   c                     t        |       S )z"Absolute value builder: rank.abs()r=  r%   s    r'   r  zRank.abs  r@  r(   c                     t        |       S )zExponential: e^rank)Expr%   s    r'   r  zRank.exp  r@  r(   c                     t        |       S )zNatural logarithm: ln(rank))Logr%   s    r'   r  zRank.log  r@  r(   Maxc                 j   t        |t        t        f      rt        |      n|}t        | t              rKt        |t              r"t	        | j
                  |j
                  z         S t	        | j
                  |gz         S t        |t              rt	        | g|j
                  z         S t	        | |g      S )z1Maximum of this rank and another: rank.max(rank2))rH   r   r  r  rF  r  r   s      r'   r  zRank.max      #-ec5\#BSZ
 dC *c*4::
(8(8899tzzZL011
C(v
 0 0011D*%&&r(   Minc                 j   t        |t        t        f      rt        |      n|}t        | t              rKt        |t              r"t	        | j
                  |j
                  z         S t	        | j
                  |gz         S t        |t              rt	        | g|j
                  z         S t	        | |g      S )z1Minimum of this rank and another: rank.min(rank2))rH   r   r  r  rI  r  r   s      r'   r  zRank.min  rH  r(   N)r    r/  )r    r>  )r    rC  )r    rE  )r)   r*   r+   ri   r   rS   r	   r5   rj   rO   r
   r  r   r"  r&  r*  r-  r1  r3  r6  r8  r;  r?  r  r  r  r  r  r.   r(   r'   r   r   U  s   6Ic3h I X=S#X X=6 X= X=v
'U65##56 
'5 
'!eE3J/ !E !%U65##56 %5 %
%eE3J/ %E %
'U65##56 
'5 
'!eE3J/ !E !%vuc'9!: %u %
%%s
"3 % %$
'vuc12 'u ''vuc12 'u 'r(   r   c                   2    e Zd ZU dZeed<   deeef   fdZ	y)r>  zAbsolute value of a rankr   r    c                 :    d| j                   j                         iS )Nr  r   r5   r%   s    r'   r5   zAbs.to_dict      		))+,,r(   N
r)   r*   r+   ri   r   r,   r   rS   r	   r5   r.   r(   r'   r>  r>        "
J-c3h -r(   r>  c                   <    e Zd ZU dZeed<   eed<   deeef   fdZ	y)r4  zDivision of two ranksr  r  r    c                 p    d| j                   j                         | j                  j                         diS )Nr  r  r  r  r5   r  r%   s    r'   r5   zDiv.to_dict  ,    !2!2!4tzz?Q?Q?STUUr(   NrO  r.   r(   r'   r4  r4    s%    
JKVc3h Vr(   r4  c                   2    e Zd ZU dZeed<   deeef   fdZ	y)rC  zExponentiation of a rankr   r    c                 :    d| j                   j                         iS )Nr  rM  r%   s    r'   r5   zExp.to_dict  rN  r(   NrO  r.   r(   r'   rC  rC    rP  r(   rC  c                   2    e Zd ZU dZeed<   deeef   fdZ	y)rE  zLogarithm of a rankr   r    c                 :    d| j                   j                         iS )Nr  rM  r%   s    r'   r5   zLog.to_dict  rN  r(   NrO  r.   r(   r'   rE  rE    s    
J-c3h -r(   rE  c                   8    e Zd ZU dZee   ed<   deee	f   fdZ
y)rF  zMaximum of multiple ranksr  r    c                 `    d| j                   D cg c]  }|j                          c}iS c c}w )Nr	  r  r5   r&   r  s     r'   r5   zMax.to_dict  %    djj99::9ro   Nr)   r*   r+   ri   r   r   r,   r   rS   r	   r5   r.   r(   r'   rF  rF    #    #:;c3h ;r(   rF  c                   8    e Zd ZU dZee   ed<   deee	f   fdZ
y)rI  zMinimum of multiple ranksr  r    c                 `    d| j                   D cg c]  }|j                          c}iS c c}w )Nr
  r\  r]  s     r'   r5   zMin.to_dict  r^  ro   Nr_  r.   r(   r'   rI  rI    r`  r(   rI  c                   8    e Zd ZU dZee   ed<   deee	f   fdZ
y)r/  z Multiplication of multiple ranksr  r    c                 `    d| j                   D cg c]  }|j                          c}iS c c}w )Nr  r\  r]  s     r'   r5   zMul.to_dict  r^  ro   Nr_  r.   r(   r'   r/  r/    s#    *:;c3h ;r(   r/  c                       e Zd ZU dZeeee   edddf   e	d<   e
j                  Zeeef   e	d<   dZee	d<   d	Zee   e	d
<   dZee	d<   deeef   fdZy	)r  a  KNN-based ranking

    Args:
        query: The query for KNN search. Can be:
               - A string (will be automatically embedded using the collection's embedding function)
               - A dense vector (list or numpy array)
               - A sparse vector (SparseVector dict)
        key: The embedding key to search against. Can be:
             - Key.EMBEDDING (default) - searches the main embedding field
             - A metadata field name (e.g., "my_custom_field") - searches that metadata field
        limit: Maximum number of results to consider (default: 16)
        default: Default score for records not in KNN results (default: None)
        return_rank: If True, return the rank position (0, 1, 2, ...) instead of distance (default: False)

    Examples:
        # Search with string query (automatically embedded)
        Knn(query="hello world")  # Will use collection's embedding function

        # Search main embeddings with vectors (equivalent forms)
        Knn(query=[0.1, 0.2])  # Uses default key="#embedding"
        Knn(query=[0.1, 0.2], key=K.EMBEDDING)
        Knn(query=[0.1, 0.2], key="#embedding")

        # Search sparse embeddings stored in metadata with string
        Knn(query="hello world", key="custom_embedding")  # Will use schema's embedding function

        # Search sparse embeddings stored in metadata with vector
        Knn(query=my_vector, key="custom_embedding")  # Example: searches a metadata field
    zNDArray[np.float32]zNDArray[np.float64]zNDArray[np.int32]r   ru   r   r   Nr   Fr   r    c                    | j                   }t        |t              r|j                         }n*t        |t        j
                        r|j                         }| j                  }t        |t              r|j                  }||| j                  d}| j                  | j                  |d<   | j                  r| j                  |d<   d|iS )N)r   ru   r   r   r   r   )r   rH   r   r5   r  r  tolistru   rT   r   r   r   r   )r&   query_value	key_valuer]   s       r'   r5   zKnn.to_dict(  s    jjk<0%--/KRZZ0%,,.KHH	i%!I 'y4::N <<# $F9$($4$4F=!r(   )r)   r*   r+   ri   r
   rS   r   r  r   r,   Kr   ru   rT   r   r   r   r   r   r   r   r	   r5   r.   r(   r'   r  r    s~    < U	  ;;CsCx&E3O#GXe_#K c3h  r(   r  c                   <    e Zd ZU dZeed<   eed<   deeef   fdZ	y)r(  zSubtraction of two ranksr  r  r    c                 p    d| j                   j                         | j                  j                         diS )Nr  rS  rT  r%   s    r'   r5   zSub.to_dictI  rU  r(   NrO  r.   r(   r'   r(  r(  B  s%    "
JKVc3h Vr(   r(  c                   8    e Zd ZU dZee   ed<   deee	f   fdZ
y)r  zSummation of multiple ranksr  r    c                 `    d| j                   D cg c]  }|j                          c}iS c c}w )Nr   r\  r]  s     r'   r5   zSum.to_dictS  r^  ro   Nr_  r.   r(   r'   r  r  M  s#    %:;c3h ;r(   r  c                   2    e Zd ZU dZeed<   deeef   fdZ	y)r  zConstant rank valuer`   r    c                     d| j                   iS )Nr   )r`   r%   s    r'   r5   zVal.to_dict]  s    

##r(   N)
r)   r*   r+   ri   r  r,   r   rS   r	   r5   r.   r(   r'   r  r  W  s    L$c3h $r(   r  c                   n    e Zd ZU dZee   ed<   dZeed<   dZ	e
ee      ed<   dZeed<   d	eeef   fd
Zy)Rrfa  Reciprocal Rank Fusion for combining multiple ranking strategies.

    RRF formula: score = -sum(weight_i / (k + rank_i)) for each ranking strategy
    The negative is used because RRF produces higher scores for better results,
    but Chroma uses ascending order (lower scores = better results).

    Args:
        ranks: List of Rank expressions to fuse (must have at least one)
        k: Smoothing constant (default: 60, standard in literature)
        weights: Optional weights for each ranking strategy. If not provided,
                all ranks are weighted equally (weight=1.0 each).
        normalize: If True, normalize weights to sum to 1.0 (default: False).
                  When False, weights are used as-is for relative importance.
                  When True, weights are scaled so they sum to 1.0.

    Examples:
        # Note: metadata fields (like "sparse_embedding" below) are user-defined and can store any data.
        # The field name is just an example - use whatever name matches your metadata structure.
        # Basic RRF combining KNN rankings (equal weight)
        Rrf([
            Knn(query=[0.1, 0.2], return_rank=True),
            Knn(query=another_vector, key="custom_embedding", return_rank=True)  # Example metadata field
        ])

        # Weighted RRF with relative weights (not normalized)
        Rrf(
            ranks=[
                Knn(query=[0.1, 0.2], return_rank=True),
                Knn(query=another_vector, key="custom_embedding", return_rank=True)  # Example metadata field
            weights=[2.0, 1.0],  # First ranking is 2x more important
            k=100
        )

        # Weighted RRF with normalized weights
        Rrf(
            ranks=[
                Knn(query=[0.1, 0.2], return_rank=True),
                Knn(query=another_vector, key="custom_embedding", return_rank=True)  # Example metadata field
            ],
            weights=[3.0, 1.0],  # Will be normalized to [0.75, 0.25]
            normalize=True,
            k=100
        )
    r  <   kNweightsF	normalizer    c                 N   | j                   st        d      | j                  dk  rt        d| j                         | j                  t	        | j                        t	        | j                         k7  r8t        dt	        | j                         dt	        | j                          d      t        d | j                  D              rt        d	      | j                  r| j                  nd
gt	        | j                         z  }| j                  r-t        |      }|dk(  rt        d      |D cg c]  }||z  	 }}t        || j                         D cg c]  \  }}|| j                  |z   z   }}}|d   }|dd D ]  }||z   }	 | j                         S c c}w c c}}w )zConvert RRF to a composition of existing expression operators.

        Builds: -sum(weight_i / (k + rank_i)) for each rank
        Using Python's overloaded operators for cleaner code.
        zRRF requires at least one rankr   zk must be positive, got NzNumber of weights (z) must match number of ranks ()c              3   &   K   | ]	  }|d k    yw)g        Nr.   ).0ws     r'   	<genexpr>zRrf.to_dict.<locals>.<genexpr>  s     1q1s71s   z All weights must be non-negativeg      ?z3Sum of weights must be positive when normalize=Truer:   )
r  rL   rt  ru  rN   anyrv  sumzipr5   )r&   ru  
weight_sumr{  r   termsrrf_sumterms           r'   r5   zRrf.to_dict  s    zz=>>66Q;7x@AA <<#4<< C

O3 )#dll*;)<<Z[^_c_i_i[jZkklm  1DLL11 !CDD #',,$,,SEC

O4K >>WJQ !VWW/67!q:~7G7 584LMDdfftm$MM a!"I 	%DnG	% !!## 8 Ns   1FF!)r)   r*   r+   ri   r   r   r,   rt  r   ru  r   r  rv  r   r   rS   r	   r5   r.   r(   r'   rr  rr  a  sN    +Z :AsK%)GXd5k")It($c3h ($r(   rr  c                   x    e Zd ZU dZ ee      Zeee	e
f      ed<   dee
ef   fdZedee
ef   dd fd       Zy)	Selecta  Selection configuration for search results.

    Fields can be:
    - Key.DOCUMENT - Select document key (equivalent to Key("#document"))
    - Key.EMBEDDING - Select embedding key (equivalent to Key("#embedding"))
    - Key.SCORE - Select score key (equivalent to Key("#score"))
    - Any other string - Select specific metadata property

    Note: You can use K as an alias for Key for more concise code.

    Examples:
        # Select predefined keys using K alias (K is shorthand for Key)
        from chromadb.execution.expression import K
        Select(keys={K.DOCUMENT, K.SCORE})

        # Select specific metadata properties
        Select(keys={"title", "author", "date"})

        # Mixed selection
        Select(keys={K.DOCUMENT, "title", "author"})
    default_factoryr   r    c                     g }| j                   D ]?  }t        |t              r|j                  |j                         /|j                  |       A dt        t        j                  |            iS )z9Convert the Select to a dictionary for JSON serializationr   )r   rH   rT   r   r   rM   rI   fromkeys)r&   key_stringsrt  s      r'   r5   zSelect.to_dict  sa      	&A!S!""166*""1%		& T]];7899r(   r7   c                    t        | t              s!t        dt        |       j                         | j                  dg       }t        |t        t        t        f      s!t        dt        |      j                         g }|D ]  }t        |t              s!t        dt        |      j                         |dk(  r |j                  t        j                         Z|dk(  r |j                  t        j                         |dk(  r |j                  t        j                         |dk(  r |j                  t        j                         |d	k(  r |j                  t        j                          |j                  t        |             
 dh}t        | j#                               |z
  }|rt%        d
|       t'        t        |            S )zCreate Select from dictionary.

        Examples:
        - {"keys": ["#document", "#score"]} -> Select(keys={Key.DOCUMENT, Key.SCORE})
        - {"keys": ["title", "author"]} -> Select(keys={"title", "author"})
        zExpected dict for Select, got r   z*Select keys must be a list/tuple/set, got z!Select key must be a string, got r   r   r   r   r   z Unexpected keys in Select dict: )r   )rH   rI   rJ   rK   r)   r   rM   r  r   rS   r   rT   r   r   r   r   r   r   rL   r  )r7   r   key_listrt  r   r   s         r'   rO   zSelect.from_dict  s}    $%<T$Z=P=P<QRSSxx#$uc 23<T$Z=P=P<QR 
  	(Aa%"CDGDTDTCU VWW Ez'k!-l".k!-h		* A'#	(( xdiik*\9??PQRR 3x=))r(   N)r)   r*   r+   ri   r   r   r   r   r
   rT   rS   r,   r   r	   r5   rj   rO   r.   r(   r'   r  r    sc    , "'s!;D#eCHo
;
:c3h 
: ,*S#X ,*8 ,* ,*r(   r  r   r    c                     t        t        t        t        t        f      t        |             }|D cg c]   }t        |t              r|j                  n|" c}S c c}w )z:Convert OneOrMany[Key|str] to List[str] for serialization.)r   r   r
   rT   rS   r   rH   r   )r   	keys_listrt  s      r'   _keys_to_stringsr    sG    T%S/*,B4,HII9BCAjC(AFFa/CCCs   %A.c                 b    | D cg c]  }t        |t              rt        |      n|! c}S c c}w )z3Convert List[str] to List[Key] for deserialization.)rH   rS   rT   r   rt  s     r'   _strings_to_keysr    s(    9=>AjC(CFa/>>>s   $,r_   r7   c                 
   ||    }t        |t              s#t        |  dt        |      j                         d|vrt        |  d      d|vrt        |  d      |d   }t        |t        t        f      s#t        |  dt        |      j                         |st        |  d      |d   }t        |t              s#t        |  dt        |      j                         |d	k  rt        |  d
|       t        |      |fS )ax  Parse common fields for MinK/MaxK from dict.

    Args:
        op: The operator name (e.g., "$min_k" or "$max_k")
        data: The dict containing the operator

    Returns:
        Tuple of (keys, k) where keys is List[Union[Key, str]] and k is int

    Raises:
        TypeError: If data types are invalid
        ValueError: If required fields are missing or invalid
    z requires a dict, got r   z requires 'keys' fieldrt  z requires 'k' fieldz keys must be a list, got z keys cannot be emptyz k must be an integer, got r   z k must be positive, got )
rH   rI   rJ   rK   r)   rL   rM   r  r   r  )r_   r7   agg_datar   rt  s        r'   _parse_k_aggregater  $  s"     BxHh%2$4T(^5L5L4MNOOXB45677
(B42344FDdT5M*2$8d9L9L8MNOOB44566Aa2$9$q':J:J9KLMMAvB48<==D!1$$r(   c                   J    e Zd ZdZdeeef   fdZedeeef   dd fd       Z	y)	Aggregatea5  Base class for aggregation expressions within groups.

    Aggregations determine which records to keep from each group:
    - MinK: Keep k records with minimum values (ascending order)
    - MaxK: Keep k records with maximum values (descending order)

    Examples:
        # Keep top 3 by score per group (single key)
        MinK(keys=Key.SCORE, k=3)

        # Keep top 5 by priority, then score as tiebreaker (multiple keys)
        MinK(keys=[Key("priority"), Key.SCORE], k=5)

        # Keep bottom 2 by score per group
        MaxK(keys=Key.SCORE, k=2)
    r    c                     t        d      )zGConvert the Aggregate expression to a dictionary for JSON serializationr2   r3   r%   s    r'   r5   zAggregate.to_dict^  r6   r(   r7   c                    t        | t              s!t        dt        |       j                         | st        d      t        |       dk7  rt        dt        |              t        t        | j                                     }|dk(  rt        ||       \  }}t        ||      S |dk(  rt        ||       \  }}t        ||      S t        d|       )	zCreate Aggregate expression from dictionary.

        Supports:
        - {"$min_k": {"keys": [...], "k": n}} -> MinK(keys=[...], k=n)
        - {"$max_k": {"keys": [...], "k": n}} -> MaxK(keys=[...], k=n)
        z!Expected dict for Aggregate, got zAggregate dict cannot be emptyr:   z6Aggregate dict must contain exactly one operator, got $min_kr  $max_kzUnknown aggregate operator: )rH   rI   rJ   rK   r)   rL   rN   rP   rQ   r   r  MinKMaxK)r7   r_   r   rt  s       r'   rO   zAggregate.from_dictb  s     $%?T
@S@S?TUVV=>>t9>HTT  $tyy{#$>(T2GD!TQ''8^(T2GD!TQ'';B4@AAr(   N)
r)   r*   r+   ri   r   rS   r	   r5   rj   rO   r.   r(   r'   r  r  K  sK    "Ic3h I BS#X B; B Br(   r  c                   L    e Zd ZU dZeeeef      ed<   e	ed<   de
eef   fdZy)r  z:Keep k records with minimum aggregate key values per groupr   rt  r    c                 J    dt        | j                        | j                  diS )Nr  r  r  r   rt  r%   s    r'   r5   zMinK.to_dict       #3DII#>TVVLMMr(   Nr)   r*   r+   ri   r   r
   rT   rS   r,   r   r   r	   r5   r.   r(   r'   r  r    3    D
E#s(O
$$
FNc3h Nr(   r  c                   L    e Zd ZU dZeeeef      ed<   e	ed<   de
eef   fdZy)r  z:Keep k records with maximum aggregate key values per groupr   rt  r    c                 J    dt        | j                        | j                  diS )Nr  r  r  r%   s    r'   r5   zMaxK.to_dict  r  r(   Nr  r.   r(   r'   r  r    r  r(   r  c                       e Zd ZU dZ ee      Zeee	e
f      ed<   dZee   ed<   dee
ef   fdZedee
ef   dd fd	       Zy)
GroupByad  Group results by metadata keys and aggregate within each group.

    Groups search results by one or more metadata fields, then applies an
    aggregation (MinK or MaxK) to select records within each group.
    The final output is flattened and sorted by score.

    Args:
        keys: Metadata key(s) to group by. Can be a single key or a list of keys.
              E.g., Key("category") or [Key("category"), Key("author")]
        aggregate: Aggregation to apply within each group (MinK or MaxK)

    Note: Both keys and aggregate must be specified together.

    Examples:
        # Top 3 documents per category (single key)
        GroupBy(
            keys=Key("category"),
            aggregate=MinK(keys=Key.SCORE, k=3)
        )

        # Top 2 per (year, category) combination (multiple keys)
        GroupBy(
            keys=[Key("year"), Key("category")],
            aggregate=MinK(keys=Key.SCORE, k=2)
        )

        # Top 1 per category by priority, score as tiebreaker
        GroupBy(
            keys=Key("category"),
            aggregate=MinK(keys=[Key("priority"), Key.SCORE], k=1)
        )
    r  r   N	aggregater    c                     | j                   r| j                  i S dt        | j                         i}| j                  j                         |d<   |S )z:Convert the GroupBy to a dictionary for JSON serializationr   r  )r   r  r  r5   r   s     r'   r5   zGroupBy.to_dict  sI     yyDNN2I"(*:499*E!F"nn446{r(   r7   c                    t        | t              s!t        dt        |       j                         | s
t               S d| vrt        d      d| vrt        d      | d   }t        |t        t        f      s!t        dt        |      j                         |st        d      | d   }t        |t              s!t        dt        |      j                         t        j                  |      }t        t        |      |	      S )
zCreate GroupBy from dictionary.

        Examples:
        - {} -> GroupBy() (default, no grouping)
        - {"keys": ["category"], "aggregate": {"$min_k": {"keys": ["#score"], "k": 3}}}
        zExpected dict for GroupBy, got r   zGroupBy requires 'keys' fieldr  z"GroupBy requires 'aggregate' fieldz!GroupBy keys must be a list, got zGroupBy keys cannot be emptyz&GroupBy aggregate must be a dict, got )r   r  )rH   rI   rJ   rK   r)   r  rL   rM   r  r  rO   r  )r7   r   aggregate_datar  s       r'   rO   zGroupBy.from_dict  s    $%=d4j>Q>Q=RSTT 9 <==d"ABBF|$u.?T
@S@S?TUVV;<<k*.$/8n9M9V9V8WX  ''7	,T2iHHr(   )r)   r*   r+   ri   r   rM   r   r   r
   rT   rS   r,   r  r   r  r   r	   r5   rj   rO   r.   r(   r'   r  r    sw    B (-T'BD)E#s(O
$B%)Ix	")c3h  !IS#X !I9 !I !Ir(   r  )Qdataclassesr   r   typingr   r   r   r   r	   r
   r   numpyr  numpy.typingr   chromadb.api.typesr   r   r   r   r   r   r   r   r   r   chromadb.typesr   r   r   r   r0   rb   rg   rt   r{   r   r   r   r   r   r   r   r   r   r   rT   r   r   r   r   r   rj  r   r   r   r   r   r>  r4  rC  rE  rF  rI  r/  r  r(  r  r  rr  r  rS   r  r  r  r   r  r  r  r  r  r.   r(   r'   <module>r     s7   ( > > >       
 
 
 G! G! G!T @% @ @ ? ? ? / / / / / / / / / 0% 0 0 / / / 0% 0 0 0 0 0 1% 1 1 7u 7 7 ;% ; ; 4E 4 4 8u 8 8b/ b/L 
U;L!;M	  ) ) )   
 .1 .1 .1b   0 [' [' ['|
 -$ - - V$ V V -$ - - -$ - - ;$ ; ; ;$ ; ; ;$ ; ; C $ C  C L V$ V V ;$ ; ; $$ $ $ [$$ [$ [$| R* R* R*pD9U38_5 D$s) D?5cE#s(O!;< ?eCQTHoAV ?
$%$%S>$%
4c3h #%&$%N 2B 2B 2Bj N9 N N N9 N N PI PI PIr(   