U
    DA·fà  ã                
   @   s  d dl mZmZmZmZmZmZmZ d dlm	Z	m
Z
 d dlmZmZ d dlmZ d dlmZmZ deeee  ee eeedf  eeeef  ee dœd	d
„Zdeeeeef  eeeef  eeeef  eeedf  eeeef  ee	 dœdd„ZdS )é    )ÚAnyÚDictÚListÚOptionalÚTupleÚTypeÚUnion)Ú	ComponentÚ	component)Údefault_from_dictÚdefault_to_dict)ÚDocument)ÚDocumentStoreÚDuplicatePolicyN.)ÚnameÚ	documentsÚdocuments_countÚbasesÚextra_fieldsÚreturnc                    sð   ˆ dk	rˆdkrt ˆ ƒ‰nˆdkr&d‰ttdf dœ‡fdd„}dttttf  tt dœ‡ fdd„}t	j
ftt t	dd	œd
d„}tt ddœdd„}tttf dœdd„}	|||||	ttƒdœ}
|dk	rÒ|
|–}
|dkràtf}t| ||
ƒ}|S )aë  
    Utility function to create a DocumentStore class with the given name and list of documents.

    If `documents` is set but `documents_count` is not, `documents_count` will be the length
    of `documents`.
    If both are set explicitly they don't influence each other.

    `write_documents()` and `delete_documents()` are no-op.
    You can override them using `extra_fields`.

    ### Usage

    Create a DocumentStore class that returns no documents:
    ```python
    MyFakeStore = document_store_class("MyFakeComponent")
    document_store = MyFakeStore()
    assert document_store.documents_count() == 0
    assert document_store.filter_documents() == []
    ```

    Create a DocumentStore class that returns a single document:
    ```python
    doc = Document(id="fake_id", content="Fake content")
    MyFakeStore = document_store_class("MyFakeComponent", documents=[doc])
    document_store = MyFakeStore()
    assert document_store.documents_count() == 1
    assert document_store.filter_documents() == [doc]
    ```

    Create a DocumentStore class that returns no document but returns a custom count:
    ```python
    MyFakeStore = document_store_class("MyFakeComponent", documents_count=100)
    document_store = MyFakeStore()
    assert document_store.documents_count() == 100
    assert document_store.filter_documents() == []
    ```

    Create a DocumentStore class that returns a document and a custom count:
    ```python
    doc = Document(id="fake_id", content="Fake content")
    MyFakeStore = document_store_class("MyFakeComponent", documents=[doc], documents_count=100)
    document_store = MyFakeStore()
    assert document_store.documents_count() == 100
    assert document_store.filter_documents() == [doc]
    ```

    Create a DocumentStore class with a custom base class:
    ```python
    MyFakeStore = document_store_class(
        "MyFakeStore",
        bases=(MyBaseClass,)
    )
    document_store = MyFakeStore()
    assert isinstance(store, MyBaseClass)
    ```

    Create a DocumentStore class with an extra field `my_field`:
    ```python
    MyFakeStore = document_store_class(
        "MyFakeStore",
        extra_fields={"my_field": 10}
    )
    document_store = MyFakeStore()
    assert document_store.my_field == 10
    ```
    Nr   )r   c                    s   ˆ S ©N© ©Úself)r   r   ú</tmp/pip-unpacked-wheel-z752163x/haystack/testing/factory.pyÚcount_documents[   s    z-document_store_class.<locals>.count_documents)Úfiltersr   c                    s   ˆ d k	rˆ S g S r   r   )r   r   )r   r   r   Úfilter_documents^   s    z.document_store_class.<locals>.filter_documents)r   Úpolicyr   c                 S   s   d S r   r   )r   r   r   r   r   r   Úwrite_documentsc   s    z-document_store_class.<locals>.write_documents)Údocument_idsr   c                 S   s   d S r   r   )r   r    r   r   r   Údelete_documentsf   s    z.document_store_class.<locals>.delete_documentsc                 S   s   t | ƒS r   ©r   r   r   r   r   Úto_dicti   s    z%document_store_class.<locals>.to_dict)r   r   r   r!   r#   Ú	from_dict)N)Úlenr   Úintr   r   Ústrr   r   r   r   ÚFAILÚclassmethodr   ÚobjectÚtype)r   r   r   r   r   r   r   r   r!   r#   ÚfieldsÚclsr   )r   r   r   Údocument_store_class   s,    I
&ú	r.   )r   Úinput_typesÚoutput_typesÚoutputr   r   r   c                    sÆ   ˆ dkrdt i‰ ˆdkr4ˆdk	r4dd„ ˆ ¡ D ƒ‰nˆdkrHdtdƒi‰‡ ‡fdd„}‡‡fdd„}d	d
„ }ttt f dœdd„}	|||t|	ƒdœ}
|dk	r¤|
|–}
|dkr²tf}t| ||
ƒ}t|ƒS )aÖ	  
    Utility class to create a Component class with the given name and input and output types.

    If `output` is set but `output_types` is not, `output_types` will be set to the types of the values in `output`.
    Though if `output_types` is set but `output` is not the component's `run` method will return a dictionary
    of the same keys as `output_types` all with a value of None.

    ### Usage

    Create a component class with default input and output types:
    ```python
    MyFakeComponent = component_class_factory("MyFakeComponent")
    component = MyFakeComponent()
    output = component.run(value=1)
    assert output == {"value": None}
    ```

    Create a component class with an "value" input of type `int` and with a "value" output of `10`:
    ```python
    MyFakeComponent = component_class_factory(
        "MyFakeComponent",
        input_types={"value": int},
        output={"value": 10}
    )
    component = MyFakeComponent()
    output = component.run(value=1)
    assert output == {"value": 10}
    ```

    Create a component class with a custom base class:
    ```python
    MyFakeComponent = component_class_factory(
        "MyFakeComponent",
        bases=(MyBaseClass,)
    )
    component = MyFakeComponent()
    assert isinstance(component, MyBaseClass)
    ```

    Create a component class with an extra field `my_field`:
    ```python
    MyFakeComponent = component_class_factory(
        "MyFakeComponent",
        extra_fields={"my_field": 10}
    )
    component = MyFakeComponent()
    assert component.my_field == 10
    ```

    Args:
    name: Name of the component class
    input_types: Dictionary of string and type that defines the inputs of the component,
        if set to None created component will expect a single input "value" of Any type.
        Defaults to None.
    output_types: Dictionary of string and type that defines the outputs of the component,
        if set to None created component will return a single output "value" of NoneType and None value.
        Defaults to None.
    output: Actual output dictionary returned by the created component run,
        is set to None it will return a dictionary of string and None values.
        Keys will be the same as the keys of output_types. Defaults to None.
    bases: Base classes for this component, if set to None only base is object. Defaults to None.
    extra_fields: Extra fields for the Component, defaults to None.

    :return: A class definition that can be used as a component.
    NÚvaluec                 S   s   i | ]\}}|t |ƒ“qS r   )r+   )Ú.0Úkeyr2   r   r   r   Ú
<dictcomp>Ë   s      z#component_class.<locals>.<dictcomp>c                    s    t j| fˆ Ž t j| fˆŽ d S r   )r
   Zset_input_typesZset_output_typesr   )r/   r0   r   r   ÚinitÏ   s    zcomponent_class.<locals>.initc                    s   ˆ d k	rˆ S dd„ ˆ  ¡ D ƒS )Nc                 S   s   i | ]
}|d “qS r   r   )r3   r   r   r   r   r5   Ù   s      z0component_class.<locals>.run.<locals>.<dictcomp>)Úkeys)r   Úkwargs)r1   r0   r   r   ÚrunÖ   s    zcomponent_class.<locals>.runc                 S   s   t | ƒS r   r"   r   r   r   r   r#   Û   s    z component_class.<locals>.to_dict)Údatac                 S   s
   t | |ƒS r   )r   )r-   r:   r   r   r   r$   Þ   s    z"component_class.<locals>.from_dict)Ú__init__r9   r#   r$   )r   Úitemsr+   r   r'   r)   r*   r
   )r   r/   r0   r1   r   r   r6   r9   r#   r$   r,   r-   r   )r/   r1   r0   r   Úcomponent_class   s"    Ir=   )NNNN)NNNNN)Útypingr   r   r   r   r   r   r   Zhaystack.core.componentr	   r
   Zhaystack.core.serializationr   r   Zhaystack.dataclassesr   Zhaystack.document_stores.typesr   r   r'   r&   r+   r.   r=   r   r   r   r   Ú<module>   s<   $    û
út     úù