mirror of
https://github.com/hwchase17/langchain.git
synced 2025-09-21 10:31:23 +00:00
multiple: langchain 0.2 in master (#21191)
0.2rc migrations - [x] Move memory - [x] Move remaining retrievers - [x] graph_qa chains - [x] some dependency from evaluation code potentially on math utils - [x] Move openapi chain from `langchain.chains.api.openapi` to `langchain_community.chains.openapi` - [x] Migrate `langchain.chains.ernie_functions` to `langchain_community.chains.ernie_functions` - [x] migrate `langchain/chains/llm_requests.py` to `langchain_community.chains.llm_requests` - [x] Moving `langchain_community.cross_enoders.base:BaseCrossEncoder` -> `langchain_community.retrievers.document_compressors.cross_encoder:BaseCrossEncoder` (namespace not ideal, but it needs to be moved to `langchain` to avoid circular deps) - [x] unit tests langchain -- add pytest.mark.community to some unit tests that will stay in langchain - [x] unit tests community -- move unit tests that depend on community to community - [x] mv integration tests that depend on community to community - [x] mypy checks Other todo - [x] Make deprecation warnings not noisy (need to use warn deprecated and check that things are implemented properly) - [x] Update deprecation messages with timeline for code removal (likely we actually won't be removing things until 0.4 release) -- will give people more time to transition their code. - [ ] Add information to deprecation warning to show users how to migrate their code base using langchain-cli - [ ] Remove any unnecessary requirements in langchain (e.g., is SQLALchemy required?) --------- Co-authored-by: Erick Friis <erick@langchain.dev>
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.astradb import AstraDBTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = AstraDBTranslator()
|
||||
|
||||
|
||||
def test_visit_comparison_lt() -> None:
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="qty", value=20)
|
||||
expected = {"qty": {"$lt": 20}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_eq() -> None:
|
||||
comp = Comparison(comparator=Comparator.EQ, attribute="qty", value=10)
|
||||
expected = {"qty": {"$eq": 10}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_ne() -> None:
|
||||
comp = Comparison(comparator=Comparator.NE, attribute="name", value="foo")
|
||||
expected = {"name": {"$ne": "foo"}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_in() -> None:
|
||||
comp = Comparison(comparator=Comparator.IN, attribute="name", value="foo")
|
||||
expected = {"name": {"$in": ["foo"]}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_nin() -> None:
|
||||
comp = Comparison(comparator=Comparator.NIN, attribute="name", value="foo")
|
||||
expected = {"name": {"$nin": ["foo"]}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.GTE, attribute="qty", value=10),
|
||||
Comparison(comparator=Comparator.LTE, attribute="qty", value=20),
|
||||
Comparison(comparator=Comparator.EQ, attribute="name", value="foo"),
|
||||
],
|
||||
)
|
||||
expected = {
|
||||
"$and": [
|
||||
{"qty": {"$gte": 10}},
|
||||
{"qty": {"$lte": 20}},
|
||||
{"name": {"$eq": "foo"}},
|
||||
]
|
||||
}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_no_filter() -> None:
|
||||
query = "What is the capital of France?"
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_one_attr() -> None:
|
||||
query = "What is the capital of France?"
|
||||
comp = Comparison(comparator=Comparator.IN, attribute="qty", value=[5, 15, 20])
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{"filter": {"qty": {"$in": [5, 15, 20]}}},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_deep_nesting() -> None:
|
||||
query = "What is the capital of France?"
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="name", value="foo"),
|
||||
Operation(
|
||||
operator=Operator.OR,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.GT, attribute="qty", value=6),
|
||||
Comparison(
|
||||
comparator=Comparator.NIN,
|
||||
attribute="tags",
|
||||
value=["bar", "foo"],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"filter": {
|
||||
"$and": [
|
||||
{"name": {"$eq": "foo"}},
|
||||
{"$or": [{"qty": {"$gt": 6}}, {"tags": {"$nin": ["bar", "foo"]}}]},
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,90 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.chroma import ChromaTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = ChromaTranslator()
|
||||
|
||||
|
||||
def test_visit_comparison() -> None:
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=["1", "2"])
|
||||
expected = {"foo": {"$lt": ["1", "2"]}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.LT, attribute="abc", value=["1", "2"]),
|
||||
],
|
||||
)
|
||||
expected = {
|
||||
"$and": [
|
||||
{"foo": {"$lt": 2}},
|
||||
{"bar": {"$eq": "baz"}},
|
||||
{"abc": {"$lt": ["1", "2"]}},
|
||||
]
|
||||
}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query() -> None:
|
||||
query = "What is the capital of France?"
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=["1", "2"])
|
||||
expected = (
|
||||
query,
|
||||
{"filter": {"foo": {"$lt": ["1", "2"]}}},
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.LT, attribute="abc", value=["1", "2"]),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"filter": {
|
||||
"$and": [
|
||||
{"foo": {"$lt": 2}},
|
||||
{"bar": {"$eq": "baz"}},
|
||||
{"abc": {"$lt": ["1", "2"]}},
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,52 @@
|
||||
from typing import Any, Tuple
|
||||
|
||||
import pytest
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.dashvector import DashvectorTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = DashvectorTranslator()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"triplet",
|
||||
[
|
||||
(Comparator.EQ, 2, "foo = 2"),
|
||||
(Comparator.LT, 2, "foo < 2"),
|
||||
(Comparator.LTE, 2, "foo <= 2"),
|
||||
(Comparator.GT, 2, "foo > 2"),
|
||||
(Comparator.GTE, 2, "foo >= 2"),
|
||||
(Comparator.LIKE, "bar", "foo LIKE '%bar%'"),
|
||||
],
|
||||
)
|
||||
def test_visit_comparison(triplet: Tuple[Comparator, Any, str]) -> None:
|
||||
comparator, value, expected = triplet
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(
|
||||
Comparison(comparator=comparator, attribute="foo", value=value)
|
||||
)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"triplet",
|
||||
[
|
||||
(Operator.AND, "foo < 2 AND bar = 'baz'"),
|
||||
(Operator.OR, "foo < 2 OR bar = 'baz'"),
|
||||
],
|
||||
)
|
||||
def test_visit_operation(triplet: Tuple[Operator, str]) -> None:
|
||||
operator, expected = triplet
|
||||
op = Operation(
|
||||
operator=operator,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
@@ -0,0 +1,141 @@
|
||||
from typing import Any, Dict, Tuple
|
||||
|
||||
import pytest
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.databricks_vector_search import (
|
||||
DatabricksVectorSearchTranslator,
|
||||
)
|
||||
|
||||
DEFAULT_TRANSLATOR = DatabricksVectorSearchTranslator()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"triplet",
|
||||
[
|
||||
(Comparator.EQ, 2, {"foo": 2}),
|
||||
(Comparator.GT, 2, {"foo >": 2}),
|
||||
(Comparator.GTE, 2, {"foo >=": 2}),
|
||||
(Comparator.LT, 2, {"foo <": 2}),
|
||||
(Comparator.LTE, 2, {"foo <=": 2}),
|
||||
(Comparator.IN, ["bar", "abc"], {"foo": ["bar", "abc"]}),
|
||||
(Comparator.LIKE, "bar", {"foo LIKE": "bar"}),
|
||||
],
|
||||
)
|
||||
def test_visit_comparison(triplet: Tuple[Comparator, Any, str]) -> None:
|
||||
comparator, value, expected = triplet
|
||||
comp = Comparison(comparator=comparator, attribute="foo", value=value)
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation_and() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
expected = {"foo <": 2, "bar": "baz"}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation_or() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.OR,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
expected = {"foo OR bar": [2, "baz"]}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation_not() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.NOT,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value=2),
|
||||
],
|
||||
)
|
||||
expected = {"foo NOT": 2}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation_not_that_raises_for_more_than_one_filter_condition() -> None:
|
||||
with pytest.raises(Exception) as exc_info:
|
||||
op = Operation(
|
||||
operator=Operator.NOT,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert (
|
||||
str(exc_info.value) == '"not" can have only one argument in '
|
||||
"Databricks vector search"
|
||||
)
|
||||
|
||||
|
||||
def test_visit_structured_query_with_no_filter() -> None:
|
||||
query = "What is the capital of France?"
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_with_one_arg_filter() -> None:
|
||||
query = "What is the capital of France?"
|
||||
comp = Comparison(comparator=Comparator.EQ, attribute="country", value="France")
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
|
||||
expected = (query, {"filters": {"country": "France"}})
|
||||
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_with_multiple_arg_filter_and_operator() -> None:
|
||||
query = "What is the capital of France in the years between 1888 and 1900?"
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="country", value="France"),
|
||||
Comparison(comparator=Comparator.GTE, attribute="year", value=1888),
|
||||
Comparison(comparator=Comparator.LTE, attribute="year", value=1900),
|
||||
],
|
||||
)
|
||||
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
|
||||
expected = (
|
||||
query,
|
||||
{"filters": {"country": "France", "year >=": 1888, "year <=": 1900}},
|
||||
)
|
||||
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,83 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.deeplake import DeepLakeTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = DeepLakeTranslator()
|
||||
|
||||
|
||||
def test_visit_comparison() -> None:
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=["1", "2"])
|
||||
expected = "(metadata['foo'] < 1 or metadata['foo'] < 2)"
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.LT, attribute="abc", value=["1", "2"]),
|
||||
],
|
||||
)
|
||||
expected = (
|
||||
"(metadata['foo'] < 2 and metadata['bar'] == 'baz' "
|
||||
"and (metadata['abc'] < 1 or metadata['abc'] < 2))"
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query() -> None:
|
||||
query = "What is the capital of France?"
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=["1", "2"])
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{"tql": "SELECT * WHERE (metadata['foo'] < 1 or metadata['foo'] < 2)"},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.LT, attribute="abc", value=["1", "2"]),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"tql": "SELECT * WHERE "
|
||||
"(metadata['foo'] < 2 and metadata['bar'] == 'baz' and "
|
||||
"(metadata['abc'] < 1 or metadata['abc'] < 2))"
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
100
libs/community/tests/unit_tests/query_constructors/test_dingo.py
Normal file
100
libs/community/tests/unit_tests/query_constructors/test_dingo.py
Normal file
@@ -0,0 +1,100 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.dingo import DingoDBTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = DingoDBTranslator()
|
||||
|
||||
|
||||
def test_visit_comparison() -> None:
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=["1", "2"])
|
||||
expected = Comparison(comparator=Comparator.LT, attribute="foo", value=["1", "2"])
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
expected = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query() -> None:
|
||||
query = "What is the capital of France?"
|
||||
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=["1", "2"])
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"search_params": {
|
||||
"langchain_expr": Comparison(
|
||||
comparator=Comparator.LT, attribute="foo", value=["1", "2"]
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"search_params": {
|
||||
"langchain_expr": Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(
|
||||
comparator=Comparator.EQ, attribute="bar", value="baz"
|
||||
),
|
||||
],
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,316 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.elasticsearch import ElasticsearchTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = ElasticsearchTranslator()
|
||||
|
||||
|
||||
def test_visit_comparison() -> None:
|
||||
comp = Comparison(comparator=Comparator.EQ, attribute="foo", value="1")
|
||||
expected = {"term": {"metadata.foo.keyword": "1"}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_range_gt() -> None:
|
||||
comp = Comparison(comparator=Comparator.GT, attribute="foo", value=1)
|
||||
expected = {"range": {"metadata.foo": {"gt": 1}}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_range_gte() -> None:
|
||||
comp = Comparison(comparator=Comparator.GTE, attribute="foo", value=1)
|
||||
expected = {"range": {"metadata.foo": {"gte": 1}}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_range_lt() -> None:
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=1)
|
||||
expected = {"range": {"metadata.foo": {"lt": 1}}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_range_lte() -> None:
|
||||
comp = Comparison(comparator=Comparator.LTE, attribute="foo", value=1)
|
||||
expected = {"range": {"metadata.foo": {"lte": 1}}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_range_match() -> None:
|
||||
comp = Comparison(comparator=Comparator.CONTAIN, attribute="foo", value="1")
|
||||
expected = {"match": {"metadata.foo": {"query": "1"}}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_range_like() -> None:
|
||||
comp = Comparison(comparator=Comparator.LIKE, attribute="foo", value="bar")
|
||||
expected = {"match": {"metadata.foo": {"query": "bar", "fuzziness": "AUTO"}}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
expected = {
|
||||
"bool": {
|
||||
"must": [
|
||||
{"term": {"metadata.foo": 2}},
|
||||
{"term": {"metadata.bar.keyword": "baz"}},
|
||||
]
|
||||
}
|
||||
}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation_or() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.OR,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
expected = {
|
||||
"bool": {
|
||||
"should": [
|
||||
{"term": {"metadata.foo": 2}},
|
||||
{"term": {"metadata.bar.keyword": "baz"}},
|
||||
]
|
||||
}
|
||||
}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation_not() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.NOT,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
expected = {
|
||||
"bool": {
|
||||
"must_not": [
|
||||
{"term": {"metadata.foo": 2}},
|
||||
{"term": {"metadata.bar.keyword": "baz"}},
|
||||
]
|
||||
}
|
||||
}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query() -> None:
|
||||
query = "What is the capital of France?"
|
||||
|
||||
structured_query = StructuredQuery(query=query, filter=None, limit=None)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_filter() -> None:
|
||||
query = "What is the capital of France?"
|
||||
comp = Comparison(comparator=Comparator.EQ, attribute="foo", value="1")
|
||||
structured_query = StructuredQuery(query=query, filter=comp, limit=None)
|
||||
expected = (
|
||||
query,
|
||||
{"filter": [{"term": {"metadata.foo.keyword": "1"}}]},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_filter_and() -> None:
|
||||
query = "What is the capital of France?"
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(query=query, filter=op, limit=None)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"filter": [
|
||||
{
|
||||
"bool": {
|
||||
"must": [
|
||||
{"term": {"metadata.foo": 2}},
|
||||
{"term": {"metadata.bar.keyword": "baz"}},
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_complex() -> None:
|
||||
query = "What is the capital of France?"
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value=2),
|
||||
Operation(
|
||||
operator=Operator.OR,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="bar", value=1),
|
||||
Comparison(comparator=Comparator.LIKE, attribute="bar", value="10"),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(query=query, filter=op, limit=None)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"filter": [
|
||||
{
|
||||
"bool": {
|
||||
"must": [
|
||||
{"term": {"metadata.foo": 2}},
|
||||
{
|
||||
"bool": {
|
||||
"should": [
|
||||
{"range": {"metadata.bar": {"lt": 1}}},
|
||||
{
|
||||
"match": {
|
||||
"metadata.bar": {
|
||||
"query": "10",
|
||||
"fuzziness": "AUTO",
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_with_date_range() -> None:
|
||||
query = "Who was the president of France in 1995?"
|
||||
operation = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value="20"),
|
||||
Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(
|
||||
comparator=Comparator.GTE,
|
||||
attribute="timestamp",
|
||||
value={"date": "1995-01-01", "type": "date"},
|
||||
),
|
||||
Comparison(
|
||||
comparator=Comparator.LT,
|
||||
attribute="timestamp",
|
||||
value={"date": "1996-01-01", "type": "date"},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(query=query, filter=operation, limit=None)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"filter": [
|
||||
{
|
||||
"bool": {
|
||||
"must": [
|
||||
{"term": {"metadata.foo.keyword": "20"}},
|
||||
{
|
||||
"bool": {
|
||||
"must": [
|
||||
{
|
||||
"range": {
|
||||
"metadata.timestamp": {
|
||||
"gte": "1995-01-01"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"metadata.timestamp": {
|
||||
"lt": "1996-01-01"
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_with_date() -> None:
|
||||
query = "Who was the president of France on 1st of January 1995?"
|
||||
operation = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value="20"),
|
||||
Comparison(
|
||||
comparator=Comparator.EQ,
|
||||
attribute="timestamp",
|
||||
value={"date": "1995-01-01", "type": "date"},
|
||||
),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(query=query, filter=operation, limit=None)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"filter": [
|
||||
{
|
||||
"bool": {
|
||||
"must": [
|
||||
{"term": {"metadata.foo.keyword": "20"}},
|
||||
{"term": {"metadata.timestamp": "1995-01-01"}},
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,129 @@
|
||||
from typing import Any, Dict, Tuple
|
||||
|
||||
import pytest
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.milvus import MilvusTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = MilvusTranslator()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"triplet",
|
||||
[
|
||||
(Comparator.EQ, 2, "( foo == 2 )"),
|
||||
(Comparator.GT, 2, "( foo > 2 )"),
|
||||
(Comparator.GTE, 2, "( foo >= 2 )"),
|
||||
(Comparator.LT, 2, "( foo < 2 )"),
|
||||
(Comparator.LTE, 2, "( foo <= 2 )"),
|
||||
(Comparator.IN, ["bar", "abc"], "( foo in ['bar', 'abc'] )"),
|
||||
(Comparator.LIKE, "bar", '( foo like "bar%" )'),
|
||||
],
|
||||
)
|
||||
def test_visit_comparison(triplet: Tuple[Comparator, Any, str]) -> None:
|
||||
comparator, value, expected = triplet
|
||||
comp = Comparison(comparator=comparator, attribute="foo", value=value)
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
# Non-Unary operator
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.LT, attribute="abc", value="4"),
|
||||
],
|
||||
)
|
||||
|
||||
expected = '(( foo < 2 ) and ( bar == "baz" ) ' 'and ( abc < "4" ))'
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
|
||||
assert expected == actual
|
||||
|
||||
# Unary operator: normal execution
|
||||
op = Operation(
|
||||
operator=Operator.NOT,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
],
|
||||
)
|
||||
|
||||
expected = "not(( foo < 2 ))"
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
|
||||
assert expected == actual
|
||||
|
||||
# Unary operator: error
|
||||
op = Operation(
|
||||
operator=Operator.NOT,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.LT, attribute="abc", value="4"),
|
||||
],
|
||||
)
|
||||
|
||||
try:
|
||||
DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
except ValueError as e:
|
||||
assert str(e) == '"not" can have only one argument in Milvus'
|
||||
else:
|
||||
assert False, "Expected exception not raised" # No exception -> test failed
|
||||
|
||||
|
||||
def test_visit_structured_query() -> None:
|
||||
query = "What is the capital of France?"
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=454)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
|
||||
expected = (
|
||||
query,
|
||||
{"expr": "( foo < 454 )"},
|
||||
)
|
||||
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.LT, attribute="abc", value=50),
|
||||
],
|
||||
)
|
||||
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
|
||||
expected = (
|
||||
query,
|
||||
{"expr": "(( foo < 2 ) " 'and ( bar == "baz" ) ' "and ( abc < 50 ))"},
|
||||
)
|
||||
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,132 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.mongodb_atlas import MongoDBAtlasTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = MongoDBAtlasTranslator()
|
||||
|
||||
|
||||
def test_visit_comparison_lt() -> None:
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="qty", value=20)
|
||||
expected = {"qty": {"$lt": 20}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_eq() -> None:
|
||||
comp = Comparison(comparator=Comparator.EQ, attribute="qty", value=10)
|
||||
expected = {"qty": {"$eq": 10}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_ne() -> None:
|
||||
comp = Comparison(comparator=Comparator.NE, attribute="name", value="foo")
|
||||
expected = {"name": {"$ne": "foo"}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_in() -> None:
|
||||
comp = Comparison(comparator=Comparator.IN, attribute="name", value="foo")
|
||||
expected = {"name": {"$in": ["foo"]}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_nin() -> None:
|
||||
comp = Comparison(comparator=Comparator.NIN, attribute="name", value="foo")
|
||||
expected = {"name": {"$nin": ["foo"]}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.GTE, attribute="qty", value=10),
|
||||
Comparison(comparator=Comparator.LTE, attribute="qty", value=20),
|
||||
Comparison(comparator=Comparator.EQ, attribute="name", value="foo"),
|
||||
],
|
||||
)
|
||||
expected = {
|
||||
"$and": [
|
||||
{"qty": {"$gte": 10}},
|
||||
{"qty": {"$lte": 20}},
|
||||
{"name": {"$eq": "foo"}},
|
||||
]
|
||||
}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_no_filter() -> None:
|
||||
query = "What is the capital of France?"
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_one_attr() -> None:
|
||||
query = "What is the capital of France?"
|
||||
comp = Comparison(comparator=Comparator.IN, attribute="qty", value=[5, 15, 20])
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{"pre_filter": {"qty": {"$in": [5, 15, 20]}}},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_deep_nesting() -> None:
|
||||
query = "What is the capital of France?"
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="name", value="foo"),
|
||||
Operation(
|
||||
operator=Operator.OR,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.GT, attribute="qty", value=6),
|
||||
Comparison(
|
||||
comparator=Comparator.NIN,
|
||||
attribute="tags",
|
||||
value=["bar", "foo"],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"pre_filter": {
|
||||
"$and": [
|
||||
{"name": {"$eq": "foo"}},
|
||||
{"$or": [{"qty": {"$gt": 6}}, {"tags": {"$nin": ["bar", "foo"]}}]},
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,86 @@
|
||||
from typing import Any, Dict, Tuple
|
||||
|
||||
import pytest
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.myscale import MyScaleTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = MyScaleTranslator()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"triplet",
|
||||
[
|
||||
(Comparator.LT, 2, "metadata.foo < 2"),
|
||||
(Comparator.LTE, 2, "metadata.foo <= 2"),
|
||||
(Comparator.GT, 2, "metadata.foo > 2"),
|
||||
(Comparator.GTE, 2, "metadata.foo >= 2"),
|
||||
(Comparator.CONTAIN, 2, "has(metadata.foo,2)"),
|
||||
(Comparator.LIKE, "bar", "metadata.foo ILIKE '%bar%'"),
|
||||
],
|
||||
)
|
||||
def test_visit_comparison(triplet: Tuple[Comparator, Any, str]) -> None:
|
||||
comparator, value, expected = triplet
|
||||
comp = Comparison(comparator=comparator, attribute="foo", value=value)
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
expected = "metadata.foo < 2 AND metadata.bar = 'baz'"
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query() -> None:
|
||||
query = "What is the capital of France?"
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=["1", "2"])
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{"where_str": "metadata.foo < ['1', '2']"},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{"where_str": "metadata.foo < 2 AND metadata.bar = 'baz'"},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,175 @@
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.opensearch import OpenSearchTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = OpenSearchTranslator()
|
||||
|
||||
|
||||
def test_visit_comparison() -> None:
|
||||
comp = Comparison(comparator=Comparator.EQ, attribute="foo", value="10")
|
||||
expected = {"term": {"metadata.foo.keyword": "10"}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.GTE, attribute="bar", value=5),
|
||||
Comparison(comparator=Comparator.LT, attribute="bar", value=10),
|
||||
Comparison(comparator=Comparator.EQ, attribute="baz", value="abcd"),
|
||||
],
|
||||
)
|
||||
expected = {
|
||||
"bool": {
|
||||
"must": [
|
||||
{"range": {"metadata.bar": {"gte": 5}}},
|
||||
{"range": {"metadata.bar": {"lt": 10}}},
|
||||
{"term": {"metadata.baz.keyword": "abcd"}},
|
||||
]
|
||||
}
|
||||
}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query() -> None:
|
||||
query = "What is the capital of France?"
|
||||
operation = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value="20"),
|
||||
Operation(
|
||||
operator=Operator.OR,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LTE, attribute="bar", value=7),
|
||||
Comparison(
|
||||
comparator=Comparator.LIKE, attribute="baz", value="abc"
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(query=query, filter=operation, limit=None)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"filter": {
|
||||
"bool": {
|
||||
"must": [
|
||||
{"term": {"metadata.foo.keyword": "20"}},
|
||||
{
|
||||
"bool": {
|
||||
"should": [
|
||||
{"range": {"metadata.bar": {"lte": 7}}},
|
||||
{
|
||||
"fuzzy": {
|
||||
"metadata.baz": {
|
||||
"value": "abc",
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_with_date_range() -> None:
|
||||
query = "Who was the president of France in 1995?"
|
||||
operation = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value="20"),
|
||||
Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(
|
||||
comparator=Comparator.GTE,
|
||||
attribute="timestamp",
|
||||
value={"date": "1995-01-01", "type": "date"},
|
||||
),
|
||||
Comparison(
|
||||
comparator=Comparator.LT,
|
||||
attribute="timestamp",
|
||||
value={"date": "1996-01-01", "type": "date"},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(query=query, filter=operation, limit=None)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"filter": {
|
||||
"bool": {
|
||||
"must": [
|
||||
{"term": {"metadata.foo.keyword": "20"}},
|
||||
{
|
||||
"bool": {
|
||||
"must": [
|
||||
{
|
||||
"range": {
|
||||
"metadata.timestamp": {"gte": "1995-01-01"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"range": {
|
||||
"metadata.timestamp": {"lt": "1996-01-01"}
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_with_date() -> None:
|
||||
query = "Who was the president of France on 1st of January 1995?"
|
||||
operation = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value="20"),
|
||||
Comparison(
|
||||
comparator=Comparator.EQ,
|
||||
attribute="timestamp",
|
||||
value={"date": "1995-01-01", "type": "date"},
|
||||
),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(query=query, filter=operation, limit=None)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"filter": {
|
||||
"bool": {
|
||||
"must": [
|
||||
{"term": {"metadata.foo.keyword": "20"}},
|
||||
{"term": {"metadata.timestamp": "1995-01-01"}},
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,87 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
import pytest as pytest
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.pgvector import PGVectorTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = PGVectorTranslator()
|
||||
|
||||
|
||||
def test_visit_comparison() -> None:
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=1)
|
||||
expected = {"foo": {"lt": 1}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
@pytest.mark.skip("Not implemented")
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.GT, attribute="abc", value=2.0),
|
||||
],
|
||||
)
|
||||
expected = {
|
||||
"foo": {"lt": 2},
|
||||
"bar": {"eq": "baz"},
|
||||
"abc": {"gt": 2.0},
|
||||
}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query() -> None:
|
||||
query = "What is the capital of France?"
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=1)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
expected = (query, {"filter": {"foo": {"lt": 1}}})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.GT, attribute="abc", value=2.0),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"filter": {
|
||||
"and": [
|
||||
{"foo": {"lt": 2}},
|
||||
{"bar": {"eq": "baz"}},
|
||||
{"abc": {"gt": 2.0}},
|
||||
]
|
||||
}
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,75 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.pinecone import PineconeTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = PineconeTranslator()
|
||||
|
||||
|
||||
def test_visit_comparison() -> None:
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=["1", "2"])
|
||||
expected = {"foo": {"$lt": ["1", "2"]}}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
expected = {"$and": [{"foo": {"$lt": 2}}, {"bar": {"$eq": "baz"}}]}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query() -> None:
|
||||
query = "What is the capital of France?"
|
||||
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=["1", "2"])
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{"filter": {"foo": {"$lt": ["1", "2"]}}},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{"filter": {"$and": [{"foo": {"$lt": 2}}, {"bar": {"$eq": "baz"}}]}},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
122
libs/community/tests/unit_tests/query_constructors/test_redis.py
Normal file
122
libs/community/tests/unit_tests/query_constructors/test_redis.py
Normal file
@@ -0,0 +1,122 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
import pytest
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.redis import RedisTranslator
|
||||
from langchain_community.vectorstores.redis.filters import (
|
||||
RedisFilterExpression,
|
||||
RedisNum,
|
||||
RedisTag,
|
||||
RedisText,
|
||||
)
|
||||
from langchain_community.vectorstores.redis.schema import (
|
||||
NumericFieldSchema,
|
||||
RedisModel,
|
||||
TagFieldSchema,
|
||||
TextFieldSchema,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def translator() -> RedisTranslator:
|
||||
schema = RedisModel(
|
||||
text=[TextFieldSchema(name="bar")],
|
||||
numeric=[NumericFieldSchema(name="foo")],
|
||||
tag=[TagFieldSchema(name="tag")],
|
||||
)
|
||||
return RedisTranslator(schema)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("comp", "expected"),
|
||||
[
|
||||
(
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=1),
|
||||
RedisNum("foo") < 1,
|
||||
),
|
||||
(
|
||||
Comparison(comparator=Comparator.LIKE, attribute="bar", value="baz*"),
|
||||
RedisText("bar") % "baz*",
|
||||
),
|
||||
(
|
||||
Comparison(
|
||||
comparator=Comparator.CONTAIN, attribute="tag", value=["blue", "green"]
|
||||
),
|
||||
RedisTag("tag") == ["blue", "green"],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_visit_comparison(
|
||||
translator: RedisTranslator, comp: Comparison, expected: RedisFilterExpression
|
||||
) -> None:
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=1)
|
||||
expected = RedisNum("foo") < 1
|
||||
actual = translator.visit_comparison(comp)
|
||||
assert str(expected) == str(actual)
|
||||
|
||||
|
||||
def test_visit_operation(translator: RedisTranslator) -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.EQ, attribute="tag", value="high"),
|
||||
],
|
||||
)
|
||||
expected = (RedisNum("foo") < 2) & (
|
||||
(RedisText("bar") == "baz") & (RedisTag("tag") == "high")
|
||||
)
|
||||
actual = translator.visit_operation(op)
|
||||
assert str(expected) == str(actual)
|
||||
|
||||
|
||||
def test_visit_structured_query_no_filter(translator: RedisTranslator) -> None:
|
||||
query = "What is the capital of France?"
|
||||
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = translator.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query_comparison(translator: RedisTranslator) -> None:
|
||||
query = "What is the capital of France?"
|
||||
comp = Comparison(comparator=Comparator.GTE, attribute="foo", value=2)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
expected_filter = RedisNum("foo") >= 2
|
||||
actual_query, actual_filter = translator.visit_structured_query(structured_query)
|
||||
assert actual_query == query
|
||||
assert str(actual_filter["filter"]) == str(expected_filter)
|
||||
|
||||
|
||||
def test_visit_structured_query_operation(translator: RedisTranslator) -> None:
|
||||
query = "What is the capital of France?"
|
||||
op = Operation(
|
||||
operator=Operator.OR,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.CONTAIN, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
expected_filter = (RedisNum("foo") == 2) | (RedisText("bar") == "baz")
|
||||
actual_query, actual_filter = translator.visit_structured_query(structured_query)
|
||||
assert actual_query == query
|
||||
assert str(actual_filter["filter"]) == str(expected_filter)
|
@@ -0,0 +1,86 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.supabase import SupabaseVectorTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = SupabaseVectorTranslator()
|
||||
|
||||
|
||||
def test_visit_comparison() -> None:
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=["1", "2"])
|
||||
expected = "and(metadata->>foo.lt.1,metadata->>foo.lt.2)"
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.LT, attribute="abc", value=["1", "2"]),
|
||||
],
|
||||
)
|
||||
expected = (
|
||||
"and("
|
||||
"metadata->foo.lt.2,"
|
||||
"metadata->>bar.eq.baz,"
|
||||
"and(metadata->>abc.lt.1,metadata->>abc.lt.2)"
|
||||
")"
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query() -> None:
|
||||
query = "What is the capital of France?"
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=["1", "2"])
|
||||
expected = (
|
||||
query,
|
||||
{"postgrest_filter": "and(metadata->>foo.lt.1,metadata->>foo.lt.2)"},
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.LT, attribute="abc", value=["1", "2"]),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"postgrest_filter": (
|
||||
"and(metadata->foo.lt.2,metadata->>bar.eq.baz,and(metadata->>abc.lt.1,metadata->>abc.lt.2))"
|
||||
)
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,95 @@
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.tencentvectordb import (
|
||||
TencentVectorDBTranslator,
|
||||
)
|
||||
|
||||
|
||||
def test_translate_with_operator() -> None:
|
||||
query = StructuredQuery(
|
||||
query="What are songs by Taylor Swift or Katy Perry"
|
||||
" under 3 minutes long in the dance pop genre",
|
||||
filter=Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Operation(
|
||||
operator=Operator.OR,
|
||||
arguments=[
|
||||
Comparison(
|
||||
comparator=Comparator.EQ,
|
||||
attribute="artist",
|
||||
value="Taylor Swift",
|
||||
),
|
||||
Comparison(
|
||||
comparator=Comparator.EQ,
|
||||
attribute="artist",
|
||||
value="Katy Perry",
|
||||
),
|
||||
],
|
||||
),
|
||||
Comparison(comparator=Comparator.LT, attribute="length", value=180),
|
||||
],
|
||||
),
|
||||
)
|
||||
translator = TencentVectorDBTranslator()
|
||||
_, kwargs = translator.visit_structured_query(query)
|
||||
expr = '(artist = "Taylor Swift" or artist = "Katy Perry") and length < 180'
|
||||
assert kwargs["expr"] == expr
|
||||
|
||||
|
||||
def test_translate_with_in_comparison() -> None:
|
||||
# 写成Comparison的形式
|
||||
query = StructuredQuery(
|
||||
query="What are songs by Taylor Swift or Katy Perry "
|
||||
"under 3 minutes long in the dance pop genre",
|
||||
filter=Comparison(
|
||||
comparator=Comparator.IN,
|
||||
attribute="artist",
|
||||
value=["Taylor Swift", "Katy Perry"],
|
||||
),
|
||||
)
|
||||
translator = TencentVectorDBTranslator()
|
||||
_, kwargs = translator.visit_structured_query(query)
|
||||
expr = 'artist in ("Taylor Swift", "Katy Perry")'
|
||||
assert kwargs["expr"] == expr
|
||||
|
||||
|
||||
def test_translate_with_allowed_fields() -> None:
|
||||
query = StructuredQuery(
|
||||
query="What are songs by Taylor Swift or Katy Perry "
|
||||
"under 3 minutes long in the dance pop genre",
|
||||
filter=Comparison(
|
||||
comparator=Comparator.IN,
|
||||
attribute="artist",
|
||||
value=["Taylor Swift", "Katy Perry"],
|
||||
),
|
||||
)
|
||||
translator = TencentVectorDBTranslator(meta_keys=["artist"])
|
||||
_, kwargs = translator.visit_structured_query(query)
|
||||
expr = 'artist in ("Taylor Swift", "Katy Perry")'
|
||||
assert kwargs["expr"] == expr
|
||||
|
||||
|
||||
def test_translate_with_unsupported_field() -> None:
|
||||
query = StructuredQuery(
|
||||
query="What are songs by Taylor Swift or Katy Perry "
|
||||
"under 3 minutes long in the dance pop genre",
|
||||
filter=Comparison(
|
||||
comparator=Comparator.IN,
|
||||
attribute="artist",
|
||||
value=["Taylor Swift", "Katy Perry"],
|
||||
),
|
||||
)
|
||||
translator = TencentVectorDBTranslator(meta_keys=["title"])
|
||||
try:
|
||||
translator.visit_structured_query(query)
|
||||
except ValueError as e:
|
||||
assert str(e) == "Expr Filtering found Unsupported attribute: artist"
|
||||
else:
|
||||
assert False
|
@@ -0,0 +1,99 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
import pytest as pytest
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.timescalevector import (
|
||||
TimescaleVectorTranslator,
|
||||
)
|
||||
|
||||
DEFAULT_TRANSLATOR = TimescaleVectorTranslator()
|
||||
|
||||
|
||||
@pytest.mark.requires("timescale_vector")
|
||||
def test_visit_comparison() -> None:
|
||||
from timescale_vector import client
|
||||
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=1)
|
||||
expected = client.Predicates(("foo", "<", 1))
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
@pytest.mark.requires("timescale_vector")
|
||||
def test_visit_operation() -> None:
|
||||
from timescale_vector import client
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.GT, attribute="abc", value=2.0),
|
||||
],
|
||||
)
|
||||
expected = client.Predicates(
|
||||
client.Predicates(("foo", "<", 2)),
|
||||
client.Predicates(("bar", "==", "baz")),
|
||||
client.Predicates(("abc", ">", 2.0)),
|
||||
)
|
||||
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
@pytest.mark.requires("timescale_vector")
|
||||
def test_visit_structured_query() -> None:
|
||||
from timescale_vector import client
|
||||
|
||||
query = "What is the capital of France?"
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=1)
|
||||
expected = (
|
||||
query,
|
||||
{"predicates": client.Predicates(("foo", "<", 1))},
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.GT, attribute="abc", value=2.0),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"predicates": client.Predicates(
|
||||
client.Predicates(("foo", "<", 2)),
|
||||
client.Predicates(("bar", "==", "baz")),
|
||||
client.Predicates(("abc", ">", 2.0)),
|
||||
)
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,72 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.vectara import VectaraTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = VectaraTranslator()
|
||||
|
||||
|
||||
def test_visit_comparison() -> None:
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value="1")
|
||||
expected = "( doc.foo < '1' )"
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.LT, attribute="abc", value=1),
|
||||
],
|
||||
)
|
||||
expected = "( ( doc.foo < 2 ) and ( doc.bar = 'baz' ) and ( doc.abc < 1 ) )"
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query() -> None:
|
||||
query = "What is the capital of France?"
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
limit=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
comp = Comparison(comparator=Comparator.LT, attribute="foo", value=1)
|
||||
expected = (query, {"filter": "( doc.foo < 1 )"})
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
limit=None,
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.LT, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
Comparison(comparator=Comparator.LT, attribute="abc", value=1),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(query=query, filter=op, limit=None)
|
||||
expected = (
|
||||
query,
|
||||
{"filter": "( ( doc.foo < 2 ) and ( doc.bar = 'baz' ) and ( doc.abc < 1 ) )"},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
@@ -0,0 +1,150 @@
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from langchain_core.structured_query import (
|
||||
Comparator,
|
||||
Comparison,
|
||||
Operation,
|
||||
Operator,
|
||||
StructuredQuery,
|
||||
)
|
||||
|
||||
from langchain_community.query_constructors.weaviate import WeaviateTranslator
|
||||
|
||||
DEFAULT_TRANSLATOR = WeaviateTranslator()
|
||||
|
||||
|
||||
def test_visit_comparison() -> None:
|
||||
comp = Comparison(comparator=Comparator.EQ, attribute="foo", value="1")
|
||||
expected = {"operator": "Equal", "path": ["foo"], "valueText": "1"}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_integer() -> None:
|
||||
comp = Comparison(comparator=Comparator.GTE, attribute="foo", value=1)
|
||||
expected = {"operator": "GreaterThanEqual", "path": ["foo"], "valueInt": 1}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_number() -> None:
|
||||
comp = Comparison(comparator=Comparator.GT, attribute="foo", value=1.4)
|
||||
expected = {"operator": "GreaterThan", "path": ["foo"], "valueNumber": 1.4}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_boolean() -> None:
|
||||
comp = Comparison(comparator=Comparator.NE, attribute="foo", value=False)
|
||||
expected = {"operator": "NotEqual", "path": ["foo"], "valueBoolean": False}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_datetime() -> None:
|
||||
comp = Comparison(
|
||||
comparator=Comparator.LTE,
|
||||
attribute="foo",
|
||||
value={"type": "date", "date": "2023-09-13"},
|
||||
)
|
||||
expected = {
|
||||
"operator": "LessThanEqual",
|
||||
"path": ["foo"],
|
||||
"valueDate": "2023-09-13T00:00:00Z",
|
||||
}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_comparison_date() -> None:
|
||||
comp = Comparison(
|
||||
comparator=Comparator.LT,
|
||||
attribute="foo",
|
||||
value={"type": "date", "date": "2023-09-13"},
|
||||
)
|
||||
expected = {
|
||||
"operator": "LessThan",
|
||||
"path": ["foo"],
|
||||
"valueDate": "2023-09-13T00:00:00Z",
|
||||
}
|
||||
actual = DEFAULT_TRANSLATOR.visit_comparison(comp)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_operation() -> None:
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value="hello"),
|
||||
Comparison(
|
||||
comparator=Comparator.GTE,
|
||||
attribute="bar",
|
||||
value={"type": "date", "date": "2023-09-13"},
|
||||
),
|
||||
Comparison(comparator=Comparator.LTE, attribute="abc", value=1.4),
|
||||
],
|
||||
)
|
||||
expected = {
|
||||
"operands": [
|
||||
{"operator": "Equal", "path": ["foo"], "valueText": "hello"},
|
||||
{
|
||||
"operator": "GreaterThanEqual",
|
||||
"path": ["bar"],
|
||||
"valueDate": "2023-09-13T00:00:00Z",
|
||||
},
|
||||
{"operator": "LessThanEqual", "path": ["abc"], "valueNumber": 1.4},
|
||||
],
|
||||
"operator": "And",
|
||||
}
|
||||
actual = DEFAULT_TRANSLATOR.visit_operation(op)
|
||||
assert expected == actual
|
||||
|
||||
|
||||
def test_visit_structured_query() -> None:
|
||||
query = "What is the capital of France?"
|
||||
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=None,
|
||||
)
|
||||
expected: Tuple[str, Dict] = (query, {})
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
comp = Comparison(comparator=Comparator.EQ, attribute="foo", value="1")
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=comp,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{"where_filter": {"path": ["foo"], "operator": "Equal", "valueText": "1"}},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
||||
|
||||
op = Operation(
|
||||
operator=Operator.AND,
|
||||
arguments=[
|
||||
Comparison(comparator=Comparator.EQ, attribute="foo", value=2),
|
||||
Comparison(comparator=Comparator.EQ, attribute="bar", value="baz"),
|
||||
],
|
||||
)
|
||||
structured_query = StructuredQuery(
|
||||
query=query,
|
||||
filter=op,
|
||||
)
|
||||
expected = (
|
||||
query,
|
||||
{
|
||||
"where_filter": {
|
||||
"operator": "And",
|
||||
"operands": [
|
||||
{"path": ["foo"], "operator": "Equal", "valueInt": 2},
|
||||
{"path": ["bar"], "operator": "Equal", "valueText": "baz"},
|
||||
],
|
||||
}
|
||||
},
|
||||
)
|
||||
actual = DEFAULT_TRANSLATOR.visit_structured_query(structured_query)
|
||||
assert expected == actual
|
Reference in New Issue
Block a user