notionary 0.1.6__py3-none-any.whl → 0.1.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. notionary/core/database/notion_database_manager.py +146 -232
  2. notionary/core/database/notion_database_manager_factory.py +9 -52
  3. notionary/core/database/notion_database_schema.py +1 -314
  4. notionary/core/notion_client.py +2 -10
  5. notionary/core/page/{page_content_manager.py → content/page_content_manager.py} +0 -1
  6. notionary/core/page/metadata/metadata_editor.py +109 -0
  7. notionary/core/page/metadata/notion_icon_manager.py +46 -0
  8. notionary/core/page/{meta_data/metadata_editor.py → metadata/notion_page_cover_manager.py} +20 -30
  9. notionary/core/page/notion_page_manager.py +218 -59
  10. notionary/core/page/properites/database_property_service.py +330 -0
  11. notionary/core/page/properites/page_property_manager.py +146 -0
  12. notionary/core/page/{property_formatter.py → properites/property_formatter.py} +19 -20
  13. notionary/core/page/properites/property_operation_result.py +103 -0
  14. notionary/core/page/properites/property_value_extractor.py +46 -0
  15. notionary/core/page/relations/notion_page_relation_manager.py +364 -0
  16. notionary/core/page/relations/notion_page_title_resolver.py +43 -0
  17. notionary/core/page/relations/page_database_relation.py +70 -0
  18. notionary/core/page/relations/relation_operation_result.py +135 -0
  19. notionary/util/{uuid_utils.py → page_id_utils.py} +15 -0
  20. {notionary-0.1.6.dist-info → notionary-0.1.7.dist-info}/METADATA +1 -1
  21. {notionary-0.1.6.dist-info → notionary-0.1.7.dist-info}/RECORD +24 -18
  22. notionary/core/database/database_query_service.py +0 -73
  23. notionary/core/database/database_schema_service.py +0 -57
  24. notionary/core/database/notion_database_writer.py +0 -390
  25. notionary/core/database/page_service.py +0 -161
  26. {notionary-0.1.6.dist-info → notionary-0.1.7.dist-info}/WHEEL +0 -0
  27. {notionary-0.1.6.dist-info → notionary-0.1.7.dist-info}/licenses/LICENSE +0 -0
  28. {notionary-0.1.6.dist-info → notionary-0.1.7.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,5 @@
1
1
  notionary/__init__.py,sha256=5T16clJlSHFsopcPUnkGrEo8spNDUQ0i-O00UEF7nR8,320
2
- notionary/core/notion_client.py,sha256=hZLQCAC38veUdOi2NYijxDYTpwOzXHRHDPArEbsXqLk,4776
2
+ notionary/core/notion_client.py,sha256=9o9-Ki1homkSbM1C51nsaAzVPMt2d4r8cPzoX3NK_HQ,4495
3
3
  notionary/core/converters/__init__.py,sha256=GOUehJbe4BKHtec1MqL1YGu3AX8zFtkwSZfhYkY5-P0,1798
4
4
  notionary/core/converters/markdown_to_notion_converter.py,sha256=PGtg4v5lUvkXXl1Y8E6a3Mf8hEfxfhBrslPs_H_Lq_E,16564
5
5
  notionary/core/converters/notion_to_markdown_converter.py,sha256=c8GyWX8-UrNfRDk7OOBKbSEb5qOwljUCwI6g5risO2c,1287
@@ -22,25 +22,31 @@ notionary/core/converters/elements/video_element.py,sha256=xrBLY3e_SgKNamItZkfPN
22
22
  notionary/core/converters/registry/block_element_registry.py,sha256=0dpRFMM67UVmXRMP4-Ubc_uCZCVVmRKgxPpueCeknjw,8619
23
23
  notionary/core/converters/registry/block_element_registry_builder.py,sha256=yTV1GPKAN7o65r9jHIqPeBCw0ICdaUZnRC5JKNwpRq4,9227
24
24
  notionary/core/database/database_info_service.py,sha256=58k7om0UXP8w0jCJHewccG5UbOvELMBAbQvXOm7F1OM,1341
25
- notionary/core/database/database_query_service.py,sha256=ggD-Sx9GdRTeKn9ytGBxijQw6euYgV__iTpObT24ebo,2442
26
- notionary/core/database/database_schema_service.py,sha256=aVyguzw8YjgQ632TDyRCDfWWCsIok3vJ4Sx3dnG9pss,1869
27
- notionary/core/database/notion_database_manager.py,sha256=E3qUxPYEJ1drurmtZaqepskH84Iw-4RN3MyXv8cb8zQ,11443
28
- notionary/core/database/notion_database_manager_factory.py,sha256=jYQeoWV4VKyfCkbxCMVf0aeShfXDvE2EVTs3Jr--Ro8,8285
29
- notionary/core/database/notion_database_schema.py,sha256=OtAsKzga7eiWzUa4AasNO2MBOTlQERQ_9Gk22Kc6f64,12599
30
- notionary/core/database/notion_database_writer.py,sha256=qpKOSDLI89GWL1kDnzLKSY5GVIzQHVYAWUl12_n-nwU,13651
31
- notionary/core/database/page_service.py,sha256=NzKCU2G-mnmqOitNWCJ6jOr0HSv1vPi1-ScSruvFdqg,5190
25
+ notionary/core/database/notion_database_manager.py,sha256=cEQHf8bTcgA3hLMgsbMGSXhCmccmxWLQ6oOJiINR3ac,8257
26
+ notionary/core/database/notion_database_manager_factory.py,sha256=SoWUiM5zdajmR1ppYHTdPgHrdZbwuTMdoXW3_tBffyU,6831
27
+ notionary/core/database/notion_database_schema.py,sha256=WUIjG7I5kusk4GOOdmVSHIKc2Z8SeOgJ1FuGpTn4avQ,3304
32
28
  notionary/core/database/models/page_result.py,sha256=Vmm5_oYpYAkIIJVoTd1ZZGloeC3cmFLMYP255mAmtaw,233
33
- notionary/core/page/notion_page_manager.py,sha256=wNkxm4kMd6hogdrNKbHQz16EE8D5wdLy5cPIuvTypG8,5582
34
- notionary/core/page/page_content_manager.py,sha256=wx-2bW4znIaBVZeFwtoVrmlGUwHMLBPOLkQCZDIV3sA,3180
35
- notionary/core/page/property_formatter.py,sha256=X70Yfg0Y8HYLrFH7Y_BZVhhc_6b369jjn02bc5IZBBI,3780
36
- notionary/core/page/meta_data/metadata_editor.py,sha256=6v1qiTpQMWlJv5YSYiDwakllSgbOsy9mlC3jNC5BImk,2286
29
+ notionary/core/page/notion_page_manager.py,sha256=NH4mNZ9jgRxmc3gay1ymG0Qcc5k_YX9eSkCMUnB9ghw,13247
30
+ notionary/core/page/content/page_content_manager.py,sha256=CZGb8vXWADxwo_xBrZ7mmKEW_HSFhlVNjOgWMfYgGJc,3142
31
+ notionary/core/page/metadata/metadata_editor.py,sha256=U3Ff9GRk28dqT9M1xsl6Q3Cj47-hB1n2pNJzeDXy4ks,4938
32
+ notionary/core/page/metadata/notion_icon_manager.py,sha256=v9pUG61TOT8x9UzDqBtQW6S5XQzWostq7IwrURnWvF4,1499
33
+ notionary/core/page/metadata/notion_page_cover_manager.py,sha256=nDWXeEztKyPscq5dRxIZ6d6IqV7E3vR-Qg1N8KzP_fo,1831
34
+ notionary/core/page/properites/database_property_service.py,sha256=z_HTt_HdB75ffYW5XNwfthZrjLEBXYqKrrK-iGHblek,12073
35
+ notionary/core/page/properites/page_property_manager.py,sha256=jMiSt9uzr9bKXYhZMg60LVLewp03OFYCeD_qQhKmFT0,6806
36
+ notionary/core/page/properites/property_formatter.py,sha256=N7GGf-ecUuMLvgt5T_KxabjmvUN7uJrMYFCL7438AZo,3665
37
+ notionary/core/page/properites/property_operation_result.py,sha256=BVje4SnWf2EdWQYH8sv_6rGd2dL0Owsixfn9SuJY0bk,3961
38
+ notionary/core/page/properites/property_value_extractor.py,sha256=IG8hKon83CZJ0zYJ-EtgHd2wbjoKOHdA3jB2vmR50Mw,2035
39
+ notionary/core/page/relations/notion_page_relation_manager.py,sha256=EHavK75Semzh8d7edI1ubh0SJyD8E0loNWVIsfxGAY4,12685
40
+ notionary/core/page/relations/notion_page_title_resolver.py,sha256=bV0ecP2dikr3vbTEXXsx_4jEtQtpQAHvG-wulASqj3o,1679
41
+ notionary/core/page/relations/page_database_relation.py,sha256=2WO1HFyIMQwgYoxvxBDUa_iTnJu-Y3Wkzy4JGJ4loME,2420
42
+ notionary/core/page/relations/relation_operation_result.py,sha256=XkO4rK0ha_FRsfq_Vlwp4a2cE-dGVPBrVxCXOlWqfwk,5258
37
43
  notionary/exceptions/database_exceptions.py,sha256=I-Tx6bYRLpi5pjGPtbT-Mqxvz3BFgYTiuZxknJeLxtI,2638
38
44
  notionary/exceptions/page_creation_exception.py,sha256=4v7IuZD6GsQLrqhDLriGjuG3ML638gAO53zDCrLePuU,281
39
45
  notionary/util/logging_mixin.py,sha256=fKsx9t90bwvL74ZX3dU-sXdC4TZCQyO6qU9I8txkw_U,1369
46
+ notionary/util/page_id_utils.py,sha256=vgCEp6BdsSJuEtLZVjrRAU9p6moLW-vymM7va8fhErI,1220
40
47
  notionary/util/singleton_decorator.py,sha256=GTNMfIlVNRUVMw_c88xqd12-DcqZJjmyidN54yqiNVw,472
41
- notionary/util/uuid_utils.py,sha256=qS2tdJSqw_gLyQxVIqlIdmkzGa7b9bJ-vw88RiQ-oGc,680
42
- notionary-0.1.6.dist-info/licenses/LICENSE,sha256=zOm3cRT1qD49eg7vgw95MI79rpUAZa1kRBFwL2FkAr8,1120
43
- notionary-0.1.6.dist-info/METADATA,sha256=ktC2Qs9nn2MYfiWQLt9YP_5verBw8_dPHxkxYy0Fbbc,6153
44
- notionary-0.1.6.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
45
- notionary-0.1.6.dist-info/top_level.txt,sha256=fhONa6BMHQXqthx5PanWGbPL0b8rdFqhrJKVLf_adSs,10
46
- notionary-0.1.6.dist-info/RECORD,,
48
+ notionary-0.1.7.dist-info/licenses/LICENSE,sha256=zOm3cRT1qD49eg7vgw95MI79rpUAZa1kRBFwL2FkAr8,1120
49
+ notionary-0.1.7.dist-info/METADATA,sha256=l0WogkR1uSHB6R6ZMCQPIlE4ajYyQ9HfnUDbccNYYfg,6153
50
+ notionary-0.1.7.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
51
+ notionary-0.1.7.dist-info/top_level.txt,sha256=fhONa6BMHQXqthx5PanWGbPL0b8rdFqhrJKVLf_adSs,10
52
+ notionary-0.1.7.dist-info/RECORD,,
@@ -1,73 +0,0 @@
1
- from typing import Any, AsyncGenerator, Dict, List, Optional
2
- from notionary.core.database.notion_database_schema import NotionDatabaseSchema
3
- from notionary.core.page.notion_page_manager import NotionPageManager
4
-
5
-
6
- class DatabaseQueryService:
7
- """Service für Datenbankabfragen und Iterations"""
8
-
9
- def __init__(self, schema: NotionDatabaseSchema):
10
- self._schema = schema
11
-
12
- async def get_pages(
13
- self,
14
- database_id: str,
15
- limit: int = 100,
16
- filter_conditions: Optional[Dict[str, Any]] = None,
17
- sorts: Optional[List[Dict[str, Any]]] = None,
18
- ) -> List[NotionPageManager]:
19
- """
20
- Get all pages from the database.
21
-
22
- Args:
23
- database_id: The database ID to query
24
- limit: Maximum number of pages to retrieve
25
- filter_conditions: Optional filter to apply to the database query
26
- sorts: Optional sort instructions for the database query
27
-
28
- Returns:
29
- List of NotionPageManager instances for each page
30
- """
31
- pages: List[NotionPageManager] = []
32
- count = 0
33
-
34
- async for page in self.iter_pages(
35
- database_id,
36
- page_size=min(limit, 100),
37
- filter_conditions=filter_conditions,
38
- sorts=sorts,
39
- ):
40
- pages.append(page)
41
- count += 1
42
-
43
- if count >= limit:
44
- break
45
-
46
- return pages
47
-
48
- async def iter_pages(
49
- self,
50
- database_id: str,
51
- page_size: int = 100,
52
- filter_conditions: Optional[Dict[str, Any]] = None,
53
- sorts: Optional[List[Dict[str, Any]]] = None,
54
- ) -> AsyncGenerator[NotionPageManager, None]:
55
- """
56
- Asynchronous generator that yields pages from the database.
57
-
58
- Args:
59
- database_id: The database ID to query
60
- page_size: Number of pages to fetch per request
61
- filter_conditions: Optional filter to apply to the database query
62
- sorts: Optional sort instructions for the database query
63
-
64
- Yields:
65
- NotionPageManager instances for each page
66
- """
67
- async for page_manager in self._schema.iter_database_pages(
68
- database_id=database_id,
69
- page_size=page_size,
70
- filter_conditions=filter_conditions,
71
- sorts=sorts,
72
- ):
73
- yield page_manager
@@ -1,57 +0,0 @@
1
- from typing import Dict, List
2
- from notionary.core.database.notion_database_schema import NotionDatabaseSchema
3
-
4
-
5
- class DatabaseSchemaService:
6
- """Service für den Zugriff auf Datenbankschema-Informationen"""
7
-
8
- def __init__(self, schema: NotionDatabaseSchema):
9
- self._schema = schema
10
-
11
- async def get_property_types(self) -> Dict[str, str]:
12
- """
13
- Get all property types for the database.
14
-
15
- Returns:
16
- Dictionary mapping property names to their types
17
- """
18
- return await self._schema.get_property_types()
19
-
20
- async def get_select_options(self, property_name: str) -> List[Dict[str, str]]:
21
- """
22
- Get options for a select, multi-select, or status property.
23
-
24
- Args:
25
- property_name: Name of the property
26
-
27
- Returns:
28
- List of select options with name, id, and color (if available)
29
- """
30
- options = await self._schema.get_select_options(property_name)
31
- return [
32
- {
33
- "name": option.get("name", ""),
34
- "id": option.get("id", ""),
35
- "color": option.get("color", ""),
36
- }
37
- for option in options
38
- ]
39
-
40
- async def get_relation_options(
41
- self, property_name: str, limit: int = 100
42
- ) -> List[Dict[str, str]]:
43
- """
44
- Get available options for a relation property.
45
-
46
- Args:
47
- property_name: Name of the relation property
48
- limit: Maximum number of options to retrieve
49
-
50
- Returns:
51
- List of relation options with id and title
52
- """
53
- options = await self._schema.get_relation_options(property_name, limit)
54
- return [
55
- {"id": option.get("id", ""), "title": option.get("title", "")}
56
- for option in options
57
- ]
@@ -1,390 +0,0 @@
1
- from typing import Any, Dict, List, Optional, Union, TypedDict, cast
2
- from notionary.core.database.notion_database_schema import NotionDatabaseSchema
3
- from notionary.core.notion_client import NotionClient
4
- from notionary.core.page.property_formatter import NotionPropertyFormatter
5
- from notionary.util.logging_mixin import LoggingMixin
6
-
7
-
8
- class NotionRelationItem(TypedDict):
9
- id: str
10
-
11
-
12
- class NotionRelationProperty(TypedDict):
13
- relation: List[NotionRelationItem]
14
-
15
-
16
- class NotionFormattedValue(TypedDict, total=False):
17
- title: List[Dict[str, Any]]
18
- rich_text: List[Dict[str, Any]]
19
- select: Dict[str, str]
20
- multi_select: List[Dict[str, str]]
21
- relation: List[NotionRelationItem]
22
- number: Union[int, float]
23
- date: Dict[str, str]
24
- checkbox: bool
25
- url: str
26
- email: str
27
- phone_number: str
28
-
29
-
30
- class PageCreationResponse(TypedDict):
31
- id: str
32
- parent: Dict[str, str]
33
- properties: Dict[str, Any]
34
-
35
-
36
- class NotionRelationHandler(LoggingMixin):
37
- """
38
- Handler for managing relations in Notion databases.
39
- Provides a unified interface for working with relations.
40
- """
41
-
42
- def __init__(self, client: NotionClient, db_schema: NotionDatabaseSchema) -> None:
43
- self._client = client
44
- self._db_schema = db_schema
45
- self._formatter = NotionPropertyFormatter()
46
-
47
- async def find_relation_by_title(
48
- self, database_id: str, relation_prop_name: str, title: str
49
- ) -> Optional[str]:
50
- """
51
- Finds a relation ID based on the title of the entry in the target database.
52
- """
53
- target_db_id = await self._db_schema.get_relation_database_id(
54
- relation_prop_name
55
- )
56
- if not target_db_id:
57
- self.logger.error(
58
- "No target database found for relation '%s' in database %s",
59
- relation_prop_name,
60
- database_id,
61
- )
62
- return None
63
-
64
- options = await self._db_schema.get_relation_options(relation_prop_name)
65
-
66
- for option in options:
67
- if option["title"].lower() == title.lower():
68
- self.logger.debug("Relation entry '%s' found: %s", title, option["id"])
69
- return option["id"]
70
-
71
- self.logger.warning("Relation entry '%s' not found", title)
72
- return None
73
-
74
- async def _get_title_properties(
75
- self, database_id: str, title: str
76
- ) -> Optional[Dict[str, NotionFormattedValue]]:
77
- """
78
- Determines the title property for a database and formats the value.
79
- """
80
- if not await self._db_schema.load():
81
- self.logger.error("Could not load database schema for %s", database_id)
82
- return None
83
-
84
- property_types = await self._db_schema.get_property_types()
85
-
86
- title_prop_name: Optional[str] = None
87
- for name, prop_type in property_types.items():
88
- if prop_type == "title":
89
- title_prop_name = name
90
- break
91
-
92
- if not title_prop_name:
93
- self.logger.error("No title property found in database %s", database_id)
94
- return None
95
-
96
- formatted_title = self._formatter.format_value("title", title)
97
- if not formatted_title:
98
- self.logger.error("Could not format title '%s'", title)
99
- return None
100
-
101
- return {title_prop_name: cast(NotionFormattedValue, formatted_title)}
102
-
103
-
104
- class DatabaseWritter(LoggingMixin):
105
- """
106
- Enhanced class for creating and updating pages in Notion databases.
107
- Supports both simple properties and relations.
108
- """
109
-
110
- def __init__(
111
- self, client: NotionClient, db_schema: Optional[NotionDatabaseSchema] = None
112
- ) -> None:
113
- """
114
- Initialize with a NotionClient and optionally a NotionDatabaseSchema.
115
-
116
- Args:
117
- client: The Notion API client
118
- db_schema: Optional database schema instance
119
- """
120
- self._client = client
121
- self._formatter = NotionPropertyFormatter()
122
-
123
- self._active_schema: Optional[NotionDatabaseSchema] = db_schema
124
- self._relation_handler: Optional[NotionRelationHandler] = None
125
-
126
- if db_schema:
127
- self._relation_handler = NotionRelationHandler(client, db_schema)
128
-
129
- async def _ensure_schema_for_database(self, database_id: str) -> bool:
130
- """
131
- Stellt sicher, dass ein Schema für die angegebene Datenbank geladen ist.
132
-
133
- Args:
134
- database_id: ID der Datenbank
135
-
136
- Returns:
137
- True, wenn das Schema erfolgreich geladen wurde
138
- """
139
- if self._active_schema and self._active_schema.database_id == database_id:
140
- return True
141
-
142
- self._active_schema = NotionDatabaseSchema(database_id, self._client)
143
- self._relation_handler = NotionRelationHandler(
144
- self._client, self._active_schema
145
- )
146
-
147
- return await self._active_schema.load()
148
-
149
- async def create_page(
150
- self,
151
- database_id: str,
152
- properties: Dict[str, Any],
153
- relations: Optional[Dict[str, Union[str, List[str]]]] = None,
154
- ) -> Optional[PageCreationResponse]:
155
- """
156
- Creates a new page in a database with support for relations.
157
- """
158
- # Stelle sicher, dass wir ein Schema für diese Datenbank haben
159
- if not await self._ensure_schema_for_database(database_id):
160
- self.logger.error("Could not load schema for database %s", database_id)
161
- return None
162
-
163
- formatted_props = await self._format_properties(database_id, properties)
164
- if not formatted_props:
165
- return None
166
-
167
- if relations:
168
- relation_props = await self._process_relations(database_id, relations)
169
- if relation_props:
170
- formatted_props.update(relation_props)
171
-
172
- data: Dict[str, Any] = {
173
- "parent": {"database_id": database_id},
174
- "properties": formatted_props,
175
- }
176
-
177
- result = await self._client.post("pages", data)
178
- if not result:
179
- self.logger.error("Error creating page in database %s", database_id)
180
- return None
181
-
182
- self.logger.info("Page successfully created in database %s", database_id)
183
- return cast(PageCreationResponse, result)
184
-
185
- async def update_page(
186
- self,
187
- page_id: str,
188
- properties: Optional[Dict[str, Any]] = None,
189
- relations: Optional[Dict[str, Union[str, List[str]]]] = None,
190
- ) -> Optional[Dict[str, Any]]:
191
- """
192
- Updates a page with support for relations.
193
- """
194
- page_data = await self._client.get(f"pages/{page_id}")
195
- if (
196
- not page_data
197
- or "parent" not in page_data
198
- or "database_id" not in page_data["parent"]
199
- ):
200
- self.logger.error("Could not determine database ID for page %s", page_id)
201
- return None
202
-
203
- database_id = page_data["parent"]["database_id"]
204
-
205
- # Stelle sicher, dass wir ein Schema für diese Datenbank haben
206
- if not await self._ensure_schema_for_database(database_id):
207
- self.logger.error("Could not load schema for database %s", database_id)
208
- return None
209
-
210
- if not properties and not relations:
211
- self.logger.warning("No properties or relations specified for update")
212
- return page_data
213
-
214
- update_props: Dict[str, NotionFormattedValue] = {}
215
-
216
- if properties:
217
- formatted_props = await self._format_properties(database_id, properties)
218
- if formatted_props:
219
- update_props.update(formatted_props)
220
-
221
- if relations:
222
- relation_props = await self._process_relations(database_id, relations)
223
- if relation_props:
224
- update_props.update(relation_props)
225
-
226
- if not update_props:
227
- self.logger.warning("No valid properties to update for page %s", page_id)
228
- return None
229
-
230
- data = {"properties": update_props}
231
-
232
- result = await self._client.patch(f"pages/{page_id}", data)
233
- if not result:
234
- self.logger.error("Error updating page %s", page_id)
235
- return None
236
-
237
- self.logger.info("Page %s successfully updated", page_id)
238
- return result
239
-
240
- async def delete_page(self, page_id: str) -> bool:
241
- """
242
- Deletes a page (archives it in Notion).
243
- """
244
- data = {"archived": True}
245
-
246
- result = await self._client.patch(f"pages/{page_id}", data)
247
- if not result:
248
- self.logger.error("Error deleting page %s", page_id)
249
- return False
250
-
251
- self.logger.info("Page %s successfully deleted (archived)", page_id)
252
- return True
253
-
254
- async def _format_properties(
255
- self, database_id: str, properties: Dict[str, Any]
256
- ) -> Optional[Dict[str, NotionFormattedValue]]:
257
- """
258
- Formats properties according to their types in the database.
259
- """
260
- if not self._active_schema:
261
- self.logger.error("No active schema available for database %s", database_id)
262
- return None
263
-
264
- property_types = await self._active_schema.get_property_types()
265
- if not property_types:
266
- self.logger.error(
267
- "Could not get property types for database %s", database_id
268
- )
269
- return None
270
-
271
- formatted_props: Dict[str, NotionFormattedValue] = {}
272
-
273
- for prop_name, value in properties.items():
274
- if prop_name not in property_types:
275
- self.logger.warning(
276
- "Property '%s' does not exist in database %s",
277
- prop_name,
278
- database_id,
279
- )
280
- continue
281
-
282
- prop_type = property_types[prop_name]
283
-
284
- formatted_value = self._formatter.format_value(prop_type, value)
285
- if formatted_value:
286
- formatted_props[prop_name] = cast(NotionFormattedValue, formatted_value)
287
- else:
288
- self.logger.warning(
289
- "Could not format value for property '%s' of type '%s'",
290
- prop_name,
291
- prop_type,
292
- )
293
-
294
- return formatted_props
295
-
296
- async def _process_relations(
297
- self, database_id: str, relations: Dict[str, Union[str, List[str]]]
298
- ) -> Dict[str, NotionRelationProperty]:
299
- """
300
- Processes relation properties and converts titles to IDs.
301
- """
302
- if not self._relation_handler:
303
- self.logger.error("No relation handler available")
304
- return {}
305
-
306
- formatted_relations: Dict[str, NotionRelationProperty] = {}
307
- property_types = (
308
- await self._active_schema.get_property_types()
309
- if self._active_schema
310
- else {}
311
- )
312
-
313
- for prop_name, titles in relations.items():
314
- relation_property = await self._process_single_relation(
315
- database_id, prop_name, titles, property_types
316
- )
317
- if relation_property:
318
- formatted_relations[prop_name] = relation_property
319
-
320
- return formatted_relations
321
-
322
- async def _process_single_relation(
323
- self,
324
- database_id: str,
325
- prop_name: str,
326
- titles: Union[str, List[str]],
327
- property_types: Dict[str, str],
328
- ) -> Optional[NotionRelationProperty]:
329
- """
330
- Process a single relation property and convert titles to IDs.
331
-
332
- Args:
333
- database_id: The database ID
334
- prop_name: The property name
335
- titles: The title or list of titles to convert
336
- property_types: Dictionary of property types
337
-
338
- Returns:
339
- A formatted relation property or None if invalid
340
- """
341
- if prop_name not in property_types:
342
- self.logger.warning(
343
- "Property '%s' does not exist in database %s", prop_name, database_id
344
- )
345
- return None
346
-
347
- prop_type = property_types[prop_name]
348
- if prop_type != "relation":
349
- self.logger.warning(
350
- "Property '%s' is not a relation (type: %s)", prop_name, prop_type
351
- )
352
- return None
353
-
354
- title_list: List[str] = [titles] if isinstance(titles, str) else titles
355
- relation_ids = await self._get_relation_ids(database_id, prop_name, title_list)
356
-
357
- if not relation_ids:
358
- return None
359
-
360
- return {"relation": [{"id": rel_id} for rel_id in relation_ids]}
361
-
362
- async def _get_relation_ids(
363
- self, database_id: str, prop_name: str, titles: List[str]
364
- ) -> List[str]:
365
- """
366
- Get relation IDs for a list of titles.
367
-
368
- Args:
369
- database_id: The database ID
370
- prop_name: The property name
371
- titles: List of titles to convert
372
-
373
- Returns:
374
- List of relation IDs
375
- """
376
- relation_ids: List[str] = []
377
-
378
- for title in titles:
379
- relation_id = await self._relation_handler.find_relation_by_title(
380
- database_id, prop_name, title
381
- )
382
-
383
- if relation_id:
384
- relation_ids.append(relation_id)
385
- else:
386
- self.logger.warning(
387
- "Could not find relation ID for '%s' in '%s'", title, prop_name
388
- )
389
-
390
- return relation_ids