Null search datetimes (#818)

* support null operations

* update

* only provide variables for non-null params

* test update
This commit is contained in:
Preston Rasmussen 2025-08-12 12:24:37 -04:00 committed by GitHub
parent baa6825708
commit bfe51a0fcd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 55 additions and 12 deletions

View file

@ -158,7 +158,7 @@ class Graphiti:
If not set, the Graphiti default is used.
ensure_ascii : bool, optional
Whether to escape non-ASCII characters in JSON serialization for prompts. Defaults to False.
Set to False to preserve non-ASCII characters (e.g., Korean, Japanese, Chinese) in their
Set as False to preserve non-ASCII characters (e.g., Korean, Japanese, Chinese) in their
original form, making them readable in LLM logs and improving model understanding.
Returns

View file

@ -28,6 +28,8 @@ class ComparisonOperator(Enum):
less_than = '<'
greater_than_equal = '>='
less_than_equal = '<='
is_null = 'IS NULL'
is_not_null = 'IS NOT NULL'
class DateFilter(BaseModel):
@ -64,6 +66,19 @@ def node_search_filter_query_constructor(
return filter_query, filter_params
def date_filter_query_constructor(
value_name: str, param_name: str, operator: ComparisonOperator
) -> str:
query = '(' + value_name + ' '
if operator == ComparisonOperator.is_null or operator == ComparisonOperator.is_not_null:
query += operator.value + ')'
else:
query += operator.value + ' ' + param_name + ')'
return query
def edge_search_filter_query_constructor(
filters: SearchFilters,
) -> tuple[str, dict[str, Any]]:
@ -85,10 +100,16 @@ def edge_search_filter_query_constructor(
valid_at_filter = '\nAND ('
for i, or_list in enumerate(filters.valid_at):
for j, date_filter in enumerate(or_list):
filter_params['valid_at_' + str(j)] = date_filter.date
if date_filter.comparison_operator not in [
ComparisonOperator.is_null,
ComparisonOperator.is_not_null,
]:
filter_params['valid_at_' + str(j)] = date_filter.date
and_filters = [
'(e.valid_at ' + date_filter.comparison_operator.value + f' $valid_at_{j})'
date_filter_query_constructor(
'e.valid_at', f'$valid_at_{j}', date_filter.comparison_operator
)
for j, date_filter in enumerate(or_list)
]
and_filter_query = ''
@ -110,10 +131,16 @@ def edge_search_filter_query_constructor(
invalid_at_filter = ' AND ('
for i, or_list in enumerate(filters.invalid_at):
for j, date_filter in enumerate(or_list):
filter_params['invalid_at_' + str(j)] = date_filter.date
if date_filter.comparison_operator not in [
ComparisonOperator.is_null,
ComparisonOperator.is_not_null,
]:
filter_params['invalid_at_' + str(j)] = date_filter.date
and_filters = [
'(e.invalid_at ' + date_filter.comparison_operator.value + f' $invalid_at_{j})'
date_filter_query_constructor(
'e.invalid_at', f'$invalid_at_{j}', date_filter.comparison_operator
)
for j, date_filter in enumerate(or_list)
]
and_filter_query = ''
@ -135,10 +162,16 @@ def edge_search_filter_query_constructor(
created_at_filter = ' AND ('
for i, or_list in enumerate(filters.created_at):
for j, date_filter in enumerate(or_list):
filter_params['created_at_' + str(j)] = date_filter.date
if date_filter.comparison_operator not in [
ComparisonOperator.is_null,
ComparisonOperator.is_not_null,
]:
filter_params['created_at_' + str(j)] = date_filter.date
and_filters = [
'(e.created_at ' + date_filter.comparison_operator.value + f' $created_at_{j})'
date_filter_query_constructor(
'e.created_at', f'$created_at_{j}', date_filter.comparison_operator
)
for j, date_filter in enumerate(or_list)
]
and_filter_query = ''
@ -160,10 +193,16 @@ def edge_search_filter_query_constructor(
expired_at_filter = ' AND ('
for i, or_list in enumerate(filters.expired_at):
for j, date_filter in enumerate(or_list):
filter_params['expired_at_' + str(j)] = date_filter.date
if date_filter.comparison_operator not in [
ComparisonOperator.is_null,
ComparisonOperator.is_not_null,
]:
filter_params['expired_at_' + str(j)] = date_filter.date
and_filters = [
'(e.expired_at ' + date_filter.comparison_operator.value + f' $expired_at_{j})'
date_filter_query_constructor(
'e.expired_at', f'$expired_at_{j}', date_filter.comparison_operator
)
for j, date_filter in enumerate(or_list)
]
and_filter_query = ''

View file

@ -1,7 +1,7 @@
[project]
name = "graphiti-core"
description = "A temporal graph building library"
version = "0.18.5"
version = "0.18.6"
authors = [
{ name = "Paul Paliychuk", email = "paul@getzep.com" },
{ name = "Preston Rasmussen", email = "preston@getzep.com" },

View file

@ -65,7 +65,11 @@ async def test_graphiti_init(driver):
search_filter = SearchFilters(
node_labels=['Person', 'City'],
created_at=[[DateFilter(date=utc_now(), comparison_operator=ComparisonOperator.less_than)]],
created_at=[
[DateFilter(date=None, comparison_operator=ComparisonOperator.is_null)],
[DateFilter(date=utc_now(), comparison_operator=ComparisonOperator.less_than)],
[DateFilter(date=None, comparison_operator=ComparisonOperator.is_not_null)],
],
)
results = await graphiti.search_(

2
uv.lock generated
View file

@ -746,7 +746,7 @@ wheels = [
[[package]]
name = "graphiti-core"
version = "0.18.4"
version = "0.18.6"
source = { editable = "." }
dependencies = [
{ name = "diskcache" },