
    Q
iB                        d dl mZmZ d dlmZ d dlmZ d dlmZm	Z	m
Z
mZmZmZ d dlZd dlmZmZmZ d dlmZ d dlmZmZ d d	lmZ d d
lmZ d dlmZ  ee          Z G d de          Z  G d de          Z! G d de          Z"dS )    )MappingSequence)Enum)Path)AnyDictListLiteralOptionalUnionN)	BaseModelFieldmodel_validator)r   )	BaseFieldFieldFactory)TypeInferrer)
get_loggermodel_to_dictc                       e Zd ZdZdZdZdS )StorageTypez
    Enumeration for the storage types supported in Redis.

    Attributes:
        HASH (str): Represents the 'hash' storage type in Redis.
        JSON (str): Represents the 'json' storage type in Redis.
    hashjsonN)__name__
__module____qualname____doc__HASHJSON     C:\Users\Dell Inspiron 16\Desktop\tws\AgrotaPowerBi\back-agrota-powerbi\mcp-client-agrota\venv\Lib\site-packages\redisvl/schema/schema.pyr   r      s$          DDDDr!   r   c                       e Zd ZU dZeed<   	 dZeeee         f         ed<   	 dZ	eed<   	 e
j        Ze
ed<   	 dZeee                  ed	<   dS )
	IndexInfoa  Index info includes the essential details regarding index settings,
    such as its name, prefix, key separator, storage type, and stopwords in Redis.

    In yaml format, the index info section looks like:

    .. code-block:: yaml

        index:
            name: user-index
            prefix: user
            key_separator: ':'
            storage_type: json
            stopwords: []  # Disable stopwords (STOPWORDS 0)

    In dict format, the index info section looks like:

    .. code-block:: python

        {"index": {
            "name": "user-index",
            "prefix": "user",
            "key_separator": ":",
            "storage_type": "json",
            "stopwords": ["the", "a", "an"]  # Custom stopwords
        }}

    namervlprefix:key_separatorstorage_typeN	stopwords)r   r   r   r   str__annotations__r'   r   r	   r)   r   r   r*   r+   r   r    r!   r"   r$   r$      s          8 III'$)FE#tCy.!)))
 M3? + 0L+000B%)IxS	")))^ ^r!   r$   c                   h   e Zd ZU dZeed<   	  ee          Ze	e
ef         ed<   	 dZed         ed<   	 edefd            Z ed	
          ede	e
ef         de	e
ef         fd                        Zede
dd fd            Zede	e
ef         dd fd            Zedee
         fd            Zedee         fd            Zde	e
ef         fdZdee	e
ef                  fdZde
fdZdg fde	e
ef         dedee
         dee	e
ef                  fdZde	e
ef         fdZ d!de
deddfd Z!dS )"IndexSchemaaJ  A schema definition for a search index in Redis, used in RedisVL for
    configuring index settings and organizing vector and metadata fields.

    The class offers methods to create an index schema from a YAML file or a
    Python dictionary, supporting flexible schema definitions and easy
    integration into various workflows.

    An example `schema.yaml` file might look like this:

    .. code-block:: yaml

        version: '0.1.0'

        index:
            name: user-index
            prefix: user
            key_separator: ":"
            storage_type: json

        fields:
            - name: user
              type: tag
            - name: credit_score
              type: tag
            - name: embedding
              type: vector
              attrs:
                algorithm: flat
                dims: 3
                distance_metric: cosine
                datatype: float32

    Loading the schema for RedisVL from yaml is as simple as:

    .. code-block:: python

        from redisvl.schema import IndexSchema

        schema = IndexSchema.from_yaml("schema.yaml")

    Loading the schema for RedisVL from dict is as simple as:

    .. code-block:: python

        from redisvl.schema import IndexSchema

        schema = IndexSchema.from_dict({
            "index": {
                "name": "user-index",
                "prefix": "user",
                "key_separator": ":",
                "storage_type": "json",
            },
            "fields": [
                {"name": "user", "type": "tag"},
                {"name": "credit_score", "type": "tag"},
                {
                    "name": "embedding",
                    "type": "vector",
                    "attrs": {
                        "algorithm": "flat",
                        "dims": 3,
                        "distance_metric": "cosine",
                        "datatype": "float32"
                    }
                }
            ]
        })

    Note:
        The `fields` attribute in the schema must contain unique field names to ensure
        correct and unambiguous field references.

    index)default_factoryfieldsz0.1.0versionreturnc                     t          j        di |}| t          j        k    r|j        r|j        n	d|j         |_        n1|j        #t                              d|j         d           d|_        |S )z
        Parse raw field inputs derived from YAML or dict.

        Validates and sets the 'path' attribute for fields when using JSON storage type.
        z$.NzPath attribute for field 'z(' will be ignored for HASH storage type.r    )r   create_fieldr   r   pathr%   loggerwarning)r*   field_inputsfields      r"   _make_fieldzIndexSchema._make_field   s     )99L99;+++',zH7HEJ7H7HEJJz%eeee   EJr!   before)modevaluesc                    |                     di           }t          |t                    st          di |}|                     dg           }i }t          |t                    r|                                D ]\  }}t          |t
                    r,|j        |k    rt          d| d|j         d          |||<   Ft          |t                    r? | j	        |j
        fi |}|j        |k    rt          d| d|j         d          |||<   t          d| d          nt          |t                    r`t          |t          t          f          sD|D ]@} | j	        |j
        fi |}|j        |v rt          d|j         d	          |||j        <   Ant          d
t          |                     ||d<   ||d<   |S )zV
        Validate uniqueness of field names and create valid field instances.
        r0   r2   zField name mismatch: key 'z' vs field name ''zInvalid field type for 'z': expected BaseField or dictDuplicate field name: z/. Field names must be unique across all fields.z#Fields must be a list or dict, got r    )get
isinstancer$   r   itemsr   r%   
ValueErrordictr<   r*   r   r,   bytestype)	clsr?   r0   input_fieldsprepared_fieldsr%   r;   	field_objfield_inputs	            r"   validate_and_create_fieldsz&IndexSchema.validate_and_create_fields   sX    

7B''%++ 	'&&&&Ezz(B//02 lG,, !	Y+1133  eeY// zT))(]]]PUPZ]]]   -2OD))t,,  /0B L Le L LI ~--(aaaPYP^aaa   -6OD))$V4VVV  !& h// 	Y
3,9
 9
 	Y  , 4 4'(:JJkJJ:00$llll   /4
++4 W4CUCUWWXXX*xwr!   	file_pathc                    	 t          |                                          }n%# t          $ r}t          d|           |d}~ww xY w|                                st          d| d          t          |d          5 }t          j        |          }| 	                    |          cddd           S # 1 swxY w Y   dS )aB  Create an IndexSchema from a YAML file.

        Args:
            file_path (str): The path to the YAML file.

        Returns:
            IndexSchema: The index schema.

        .. code-block:: python

            from redisvl.schema import IndexSchema
            schema = IndexSchema.from_yaml("schema.yaml")
        zInvalid file path: NSchema file z does not existr)
r   resolveOSErrorrF   existsFileNotFoundErroropenyaml	safe_loadmodel_validate)rJ   rP   fpef	yaml_datas         r"   	from_yamlzIndexSchema.from_yaml   s   	Gi((**BB 	G 	G 	G>9>>??QF	G yy{{ 	O#$M9$M$M$MNNN"c]] 	1aq))I%%i00	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1 	1s&   !$ 
AAA )B66B:=B:datac                 T    |                                 }|                     |          S )a  Create an IndexSchema from a dictionary.

        Args:
            data (Dict[str, Any]): The index schema data.

        Returns:
            IndexSchema: The index schema.

        .. code-block:: python

            from redisvl.schema import IndexSchema

            schema = IndexSchema.from_dict({
                "index": {
                    "name": "docs-index",
                    "prefix": "docs",
                    "storage_type": "hash",
                },
                "fields": [
                    {
                        "name": "doc-id",
                        "type": "tag"
                    },
                    {
                        "name": "doc-embedding",
                        "type": "vector",
                        "attrs": {
                            "algorithm": "flat",
                            "dims": 1536
                        }
                    }
                ]
            })
        )copyr[   )rJ   ra   schema_dicts      r"   	from_dictzIndexSchema.from_dict  s&    H iikk!!+...r!   c                 N    t          | j                                                  S )zA list of field names associated with the index schema.

        Returns:
            List[str]: A list of field names from the schema.
        )listr2   keys)selfs    r"   field_nameszIndexSchema.field_names/  s      DK$$&&'''r!   c                 L    d | j                                         D             }|S )ar  A list of core redis-py field definitions based on the
        current schema fields.

        Converts RedisVL field definitions into a format suitable for use with
        redis-py, facilitating the creation and management of index structures in
        the Redis database.

        Returns:
            List[RedisField]: A list of redis-py field definitions.
        c                 <    g | ]\  }}|                                 S r    )as_redis_field).0_r;   s      r"   
<listcomp>z,IndexSchema.redis_fields.<locals>.<listcomp>D  s5     *
 *
 *
'/q%E  ""*
 *
 *
r!   )r2   rE   )ri   redis_fieldss     r"   rq   zIndexSchema.redis_fields8  s6    *
 *
37;3D3D3F3F*
 *
 *
 r!   r:   c                      | j         | j        j        fi |}|j        | j        v rt          d|j         d          || j        |j        <   dS )a  Adds a single field to the index schema based on the specified field
        type and attributes.

        This method allows for the addition of individual fields to the schema,
        providing flexibility in defining the structure of the index.

        Args:
            field_inputs (Dict[str, Any]): A field to add.

        Raises:
            ValueError: If the field name or type are not provided or if the name
                already exists within the schema.

        .. code-block:: python

            # Add a tag field
            schema.add_field({"name": "user", "type": "tag"})

            # Add a vector field
            schema.add_field({
                "name": "user-embedding",
                "type": "vector",
                "attrs": {
                    "dims": 1024,
                    "algorithm": "flat",
                    "datatype": "float32"
                }
            })
        rB   z>. Field names must be unique across all fields for this index.N)r<   r0   r*   r%   r2   rF   )ri   r:   r;   s      r"   	add_fieldzIndexSchema.add_fieldI  sj    > ! !8IILII:$$ssss   #(EJr!   c                 :    |D ]}|                      |           dS )a\  Extends the schema with additional fields.

        This method allows dynamically adding new fields to the index schema. It
        processes a list of field definitions.

        Args:
            fields (List[Dict[str, Any]]): A list of fields to add.

        Raises:
            ValueError: If a field with the same name already exists in the
                schema.

        .. code-block:: python

            schema.add_fields([
                {"name": "user", "type": "tag"},
                {"name": "bio", "type": "text"},
                {
                    "name": "user-embedding",
                    "type": "vector",
                    "attrs": {
                        "dims": 1024,
                        "algorithm": "flat",
                        "datatype": "float32"
                    }
                }
            ])
        N)rs   )ri   r2   r;   s      r"   
add_fieldszIndexSchema.add_fieldsq  s2    :  	" 	"ENN5!!!!	" 	"r!   
field_namec                 h    || j         vr t                              d| d           dS | j         |= dS )zRemoves a field from the schema based on the specified name.

        This method is useful for dynamically altering the schema by removing
        existing fields.

        Args:
            field_name (str): The name of the field to be removed.
        zField 'z' does not exist in the schemaN)r2   r8   r9   )ri   rv   s     r"   remove_fieldzIndexSchema.remove_field  sD     T[((NNOZOOOPPPFK
###r!   Fstrictignore_fieldsc                 \   g }|                                 D ]\  }}||v r
	 t          j        |          }|                    t	          j        ||                                                     Z# t          $ r.}|r t          	                    d| d|            Y d}~d}~ww xY w|S )a,  Generates a list of extracted field specs from a sample data point.

        This method simplifies the process of creating a schema by inferring
        field types and attributes from sample data. It's particularly useful
        during the development process while dealing with datasets containing
        numerous fields, reducing the need for manual specification.

        Args:
            data (Dict[str, Any]): Sample data used to infer field definitions.
            strict (bool, optional): If True, raises an error on failing to
                infer a field type. Defaults to False.
            ignore_fields (List[str], optional): A list of field names to
                exclude from processing. Defaults to an empty list.

        Returns:
            Dict[str, List[Dict[str, Any]]]: A dictionary with inferred field
                types and attributes.

        Notes:
            - Vector fields are not generated by this method.
            - This method employs heuristics and may not always correctly infer
                field types.
        zError inferring field type for z: )messageN)
rE   r   inferappendr   r6   
model_dumprF   r8   warn)	ri   ra   ry   rz   r2   rv   value
field_typer]   s	            r"   generate_fieldszIndexSchema.generate_fields  s    : (*!% 	 	J]**)/66
 -""  !jll	        KK S* S SPQ S S          	 s   AA11
B);$B$$B)c                     t          | j                  d | j                                        D             | j        d}|S )zSerialize the index schema model to a dictionary, handling Enums
        and other special cases properly.

        Returns:
            Dict[str, Any]: The index schema as a dictionary.
        c                 2    g | ]\  }}t          |          S r    r   )rn   rv   r;   s      r"   rp   z'IndexSchema.to_dict.<locals>.<listcomp>  s1       ):Ue$$  r!   )r0   r2   r3   )r   r0   r2   rE   r3   )ri   dict_schemas     r"   to_dictzIndexSchema.to_dict  sV     #4:.. >Bk>O>O>Q>Q   |
 
 r!   T	overwriteNc                 B   t          |                                          }|                                r|st          d| d          t	          |d          5 }|                                 }t          j        ||d           ddd           dS # 1 swxY w Y   dS )a)  Write the index schema to a YAML file.

        Args:
            file_path (str): The path to the YAML file.
            overwrite (bool): Whether to overwrite the file if it already exists.

        Raises:
            FileExistsError: If the file already exists and overwrite is False.
        rR   z already exists.wF)	sort_keysN)r   rT   rV   FileExistsErrorrX   r   rY   dump)ri   rP   r   r\   r^   r_   s         r"   to_yamlzIndexSchema.to_yaml  s     )__$$&&99;; 	Ny 	N!"L"L"L"LMMM"c]] 	5aIIie4444	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5 	5s   ,BBB)T)"r   r   r   r   r$   r-   r   rG   r2   r   r,   r   r3   r
   staticmethodr<   r   classmethodr   rO   r`   re   propertyr	   rj   
RedisFieldrq   rs   ru   rx   boolr   r   r   r    r!   r"   r/   r/   M   s        I IV 4#(5#>#>#>FDi >>>M !(GWW'''1Y    \& _(###2S#X 24S> 2 2 2 [ $#2h 1# 1- 1 1 1 [14 $/T#s(^ $/ $/ $/ $/ [$/L (T#Y ( ( ( X( d:.    X &(d38n &( &( &( &(P"d38n!5 " " " "@$s $ $ $ $" #%	0 038n0 0 Cy	0
 
d38n	0 0 0 0dc3h    "5 5 5 5 5 5 5 5 5 5r!   r/   )#collections.abcr   r   enumr   pathlibr   typingr   r   r	   r
   r   r   rY   pydanticr   r   r   redis.commands.search.fieldr   redisvl.schema.fieldsr   r   redisvl.schema.type_utilsr   redisvl.utils.logr   redisvl.utils.utilsr   r   r8   r   r$   r/   r    r!   r"   <module>r      s   - - - - - - - -             < < < < < < < < < < < < < < < <  6 6 6 6 6 6 6 6 6 6 ; ; ; ; ; ; 9 9 9 9 9 9 9 9 2 2 2 2 2 2 ( ( ( ( ( ( - - - - - -	H		
 
 
 
 
$ 
 
 
+^ +^ +^ +^ +^	 +^ +^ +^\e5 e5 e5 e5 e5) e5 e5 e5 e5 e5r!   