Skip to content

Commit

Permalink
add database methods to query by property value
Browse files Browse the repository at this point in the history
  • Loading branch information
thrau committed Mar 30, 2024
1 parent 25695c9 commit aba8fe5
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 5 deletions.
46 changes: 41 additions & 5 deletions notion_objects/database.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import copy
import typing
import uuid
from functools import cached_property, lru_cache
from typing import Callable, Generic, Iterable, Optional, Type, TypeVar, Union
from typing import Any, Callable, Generic, Iterable, List, Optional, Type, TypeVar, Union, overload

from notion_client import APIResponseError, Client

from .objects import DynamicNotionObject, NotionObject
from .properties import ChangeTracker, Properties
from .properties import ChangeTracker, Properties, Property

_N = TypeVar("_N", bound=NotionObject)

Expand Down Expand Up @@ -44,7 +43,7 @@ def __iter__(self):
class Database(Generic[_N], Iterable[_N]):
default_page_size: int = 100

@typing.overload
@overload
def __init__(
self,
database_id: str,
Expand All @@ -54,7 +53,7 @@ def __init__(
] = None,
): ...

@typing.overload
@overload
def __init__(
self,
mapped_type: Union[Type[_N], Type[DynamicNotionObject], Callable[[DatabaseRecord], _N]],
Expand Down Expand Up @@ -134,6 +133,18 @@ def find_by_id(self, page_id: str) -> Optional[_N]:

return self.type(page)

def find_unique_by_value(self, property: Property, value: Any) -> Optional[_N]:
"""
Runs ``query_by_value`` and then returns the first element found, or None if the result was epmty.
:param property: property to look up
:param value: the value to match
:return: optional result
"""
for item in self.query_by_value(property, value):
return item
return None

def update(self, page: ChangeTracker):
try:
page_id = page.id
Expand Down Expand Up @@ -190,3 +201,28 @@ def query(self, query: Query = None) -> Iterable[_N]:

for item in IterableQueryExecutor(self.client, query=query):
yield factory(item)

def query_by_value(self, property: Property, value: Any) -> Iterable[_N]:
"""
Builds an equals filter for the given property and value, and returns an iterable of items that match the value.
Use the following pattern::
backlog = Database(BacklogItem, ...)
for ticket in backlog.query_by_value(BacklogItem.status, "In progress"):
...
:param property: the property to search for
:param value: the value
:return: a list of items, can be empty
"""
return self.query(
{
"filter": {
"property": property.field,
property.type: {
"equals": value,
},
},
}
)
5 changes: 5 additions & 0 deletions notion_objects/properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ def __set_name__(self, owner, name):
self.target_type = None

def __get__(self, instance, owner):
if instance is None:
# instance will be None when accessing the property through class access, for instance ``Page.id``. Here we
# return the Property instance itself, rather than the value. This helps with various meta operations.
return self

if self.object_locator:
return self.get(self.field, getattr(instance, self.object_locator))
else:
Expand Down

0 comments on commit aba8fe5

Please sign in to comment.