notionary 0.3.1__py3-none-any.whl → 0.4.1__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.
- notionary/__init__.py +49 -1
- notionary/blocks/client.py +37 -11
- notionary/blocks/enums.py +0 -6
- notionary/blocks/rich_text/markdown_rich_text_converter.py +49 -15
- notionary/blocks/rich_text/models.py +13 -4
- notionary/blocks/rich_text/name_id_resolver/data_source.py +9 -3
- notionary/blocks/rich_text/name_id_resolver/person.py +6 -2
- notionary/blocks/rich_text/rich_text_markdown_converter.py +10 -3
- notionary/blocks/schemas.py +33 -78
- notionary/comments/client.py +19 -6
- notionary/comments/factory.py +10 -3
- notionary/comments/schemas.py +10 -31
- notionary/comments/service.py +12 -4
- notionary/data_source/http/data_source_instance_client.py +59 -17
- notionary/data_source/properties/schemas.py +156 -115
- notionary/data_source/query/builder.py +67 -18
- notionary/data_source/query/resolver.py +16 -5
- notionary/data_source/query/schema.py +24 -6
- notionary/data_source/query/validator.py +18 -6
- notionary/data_source/schema/registry.py +31 -12
- notionary/data_source/schema/service.py +66 -20
- notionary/data_source/schemas.py +2 -2
- notionary/data_source/service.py +103 -43
- notionary/database/client.py +27 -9
- notionary/database/database_metadata_update_client.py +12 -4
- notionary/database/schemas.py +2 -2
- notionary/database/service.py +14 -9
- notionary/exceptions/__init__.py +20 -4
- notionary/exceptions/api.py +2 -2
- notionary/exceptions/base.py +1 -1
- notionary/exceptions/block_parsing.py +9 -5
- notionary/exceptions/data_source/builder.py +13 -7
- notionary/exceptions/data_source/properties.py +6 -4
- notionary/exceptions/file_upload.py +76 -0
- notionary/exceptions/properties.py +7 -5
- notionary/exceptions/search.py +10 -6
- notionary/file_upload/__init__.py +4 -0
- notionary/file_upload/client.py +128 -210
- notionary/file_upload/config/__init__.py +17 -0
- notionary/file_upload/config/config.py +39 -0
- notionary/file_upload/config/constants.py +16 -0
- notionary/file_upload/file/reader.py +28 -0
- notionary/file_upload/query/__init__.py +7 -0
- notionary/file_upload/query/builder.py +58 -0
- notionary/file_upload/query/models.py +37 -0
- notionary/file_upload/schemas.py +80 -0
- notionary/file_upload/service.py +182 -291
- notionary/file_upload/validation/factory.py +66 -0
- notionary/file_upload/validation/impl/file_name_length.py +25 -0
- notionary/file_upload/validation/models.py +134 -0
- notionary/file_upload/validation/port.py +7 -0
- notionary/file_upload/validation/service.py +17 -0
- notionary/file_upload/validation/validators/__init__.py +11 -0
- notionary/file_upload/validation/validators/file_exists.py +15 -0
- notionary/file_upload/validation/validators/file_extension.py +131 -0
- notionary/file_upload/validation/validators/file_name_length.py +21 -0
- notionary/file_upload/validation/validators/upload_limit.py +31 -0
- notionary/http/client.py +33 -30
- notionary/page/content/__init__.py +9 -0
- notionary/page/content/factory.py +21 -7
- notionary/page/content/markdown/builder.py +85 -23
- notionary/page/content/markdown/nodes/audio.py +8 -4
- notionary/page/content/markdown/nodes/base.py +3 -3
- notionary/page/content/markdown/nodes/bookmark.py +5 -3
- notionary/page/content/markdown/nodes/breadcrumb.py +2 -2
- notionary/page/content/markdown/nodes/bulleted_list.py +5 -3
- notionary/page/content/markdown/nodes/callout.py +2 -2
- notionary/page/content/markdown/nodes/code.py +5 -3
- notionary/page/content/markdown/nodes/columns.py +3 -3
- notionary/page/content/markdown/nodes/container.py +9 -5
- notionary/page/content/markdown/nodes/divider.py +2 -2
- notionary/page/content/markdown/nodes/embed.py +8 -4
- notionary/page/content/markdown/nodes/equation.py +4 -2
- notionary/page/content/markdown/nodes/file.py +8 -4
- notionary/page/content/markdown/nodes/heading.py +2 -2
- notionary/page/content/markdown/nodes/image.py +8 -4
- notionary/page/content/markdown/nodes/mixins/caption.py +5 -3
- notionary/page/content/markdown/nodes/numbered_list.py +5 -3
- notionary/page/content/markdown/nodes/paragraph.py +4 -2
- notionary/page/content/markdown/nodes/pdf.py +8 -4
- notionary/page/content/markdown/nodes/quote.py +2 -2
- notionary/page/content/markdown/nodes/space.py +2 -2
- notionary/page/content/markdown/nodes/table.py +8 -5
- notionary/page/content/markdown/nodes/table_of_contents.py +2 -2
- notionary/page/content/markdown/nodes/todo.py +15 -7
- notionary/page/content/markdown/nodes/toggle.py +2 -2
- notionary/page/content/markdown/nodes/video.py +8 -4
- notionary/page/content/markdown/structured_output/__init__.py +73 -0
- notionary/page/content/markdown/structured_output/models.py +391 -0
- notionary/page/content/markdown/structured_output/service.py +211 -0
- notionary/page/content/parser/context.py +1 -1
- notionary/page/content/parser/factory.py +26 -8
- notionary/page/content/parser/parsers/audio.py +12 -32
- notionary/page/content/parser/parsers/base.py +2 -2
- notionary/page/content/parser/parsers/bookmark.py +2 -2
- notionary/page/content/parser/parsers/breadcrumb.py +2 -2
- notionary/page/content/parser/parsers/bulleted_list.py +19 -6
- notionary/page/content/parser/parsers/callout.py +15 -5
- notionary/page/content/parser/parsers/caption.py +9 -3
- notionary/page/content/parser/parsers/code.py +21 -7
- notionary/page/content/parser/parsers/column.py +8 -4
- notionary/page/content/parser/parsers/column_list.py +19 -7
- notionary/page/content/parser/parsers/divider.py +2 -2
- notionary/page/content/parser/parsers/embed.py +2 -4
- notionary/page/content/parser/parsers/equation.py +8 -4
- notionary/page/content/parser/parsers/file.py +12 -34
- notionary/page/content/parser/parsers/file_like_block.py +109 -0
- notionary/page/content/parser/parsers/heading.py +31 -10
- notionary/page/content/parser/parsers/image.py +12 -34
- notionary/page/content/parser/parsers/numbered_list.py +18 -6
- notionary/page/content/parser/parsers/paragraph.py +3 -1
- notionary/page/content/parser/parsers/pdf.py +12 -34
- notionary/page/content/parser/parsers/quote.py +28 -9
- notionary/page/content/parser/parsers/space.py +2 -2
- notionary/page/content/parser/parsers/table.py +31 -10
- notionary/page/content/parser/parsers/table_of_contents.py +7 -3
- notionary/page/content/parser/parsers/todo.py +15 -5
- notionary/page/content/parser/parsers/toggle.py +15 -5
- notionary/page/content/parser/parsers/video.py +12 -34
- notionary/page/content/parser/post_processing/handlers/rich_text_length.py +8 -2
- notionary/page/content/parser/post_processing/handlers/rich_text_length_truncation.py +8 -2
- notionary/page/content/parser/post_processing/service.py +3 -1
- notionary/page/content/parser/pre_processsing/handlers/column_syntax.py +21 -7
- notionary/page/content/parser/pre_processsing/handlers/indentation.py +11 -4
- notionary/page/content/parser/pre_processsing/handlers/video_syntax.py +13 -6
- notionary/page/content/parser/service.py +4 -1
- notionary/page/content/renderer/context.py +15 -5
- notionary/page/content/renderer/factory.py +12 -6
- notionary/page/content/renderer/post_processing/handlers/numbered_list.py +19 -9
- notionary/page/content/renderer/renderers/audio.py +20 -23
- notionary/page/content/renderer/renderers/base.py +3 -3
- notionary/page/content/renderer/renderers/bookmark.py +3 -1
- notionary/page/content/renderer/renderers/bulleted_list.py +11 -5
- notionary/page/content/renderer/renderers/callout.py +19 -7
- notionary/page/content/renderer/renderers/captioned_block.py +11 -5
- notionary/page/content/renderer/renderers/code.py +6 -2
- notionary/page/content/renderer/renderers/column.py +3 -1
- notionary/page/content/renderer/renderers/column_list.py +3 -1
- notionary/page/content/renderer/renderers/embed.py +3 -1
- notionary/page/content/renderer/renderers/equation.py +3 -1
- notionary/page/content/renderer/renderers/file.py +20 -23
- notionary/page/content/renderer/renderers/file_like_block.py +47 -0
- notionary/page/content/renderer/renderers/heading.py +22 -8
- notionary/page/content/renderer/renderers/image.py +20 -23
- notionary/page/content/renderer/renderers/numbered_list.py +8 -3
- notionary/page/content/renderer/renderers/paragraph.py +12 -4
- notionary/page/content/renderer/renderers/pdf.py +20 -23
- notionary/page/content/renderer/renderers/quote.py +14 -6
- notionary/page/content/renderer/renderers/table.py +15 -5
- notionary/page/content/renderer/renderers/todo.py +16 -6
- notionary/page/content/renderer/renderers/toggle.py +8 -4
- notionary/page/content/renderer/renderers/video.py +20 -23
- notionary/page/content/renderer/service.py +9 -3
- notionary/page/content/service.py +21 -7
- notionary/page/content/syntax/definition/__init__.py +11 -0
- notionary/page/content/syntax/definition/models.py +57 -0
- notionary/page/content/syntax/definition/registry.py +371 -0
- notionary/page/content/syntax/prompts/__init__.py +4 -0
- notionary/page/content/syntax/prompts/models.py +11 -0
- notionary/page/content/syntax/prompts/registry.py +703 -0
- notionary/page/page_metadata_update_client.py +12 -4
- notionary/page/properties/client.py +46 -16
- notionary/page/properties/factory.py +6 -2
- notionary/page/properties/{models.py → schemas.py} +93 -107
- notionary/page/properties/service.py +111 -37
- notionary/page/schemas.py +3 -3
- notionary/page/service.py +21 -7
- notionary/shared/entity/client.py +6 -2
- notionary/shared/entity/dto_parsers.py +4 -37
- notionary/shared/entity/entity_metadata_update_client.py +25 -5
- notionary/shared/entity/schemas.py +6 -6
- notionary/shared/entity/service.py +89 -35
- notionary/shared/models/file.py +36 -6
- notionary/shared/models/icon.py +5 -12
- notionary/user/base.py +6 -2
- notionary/user/bot.py +22 -14
- notionary/user/client.py +3 -1
- notionary/user/person.py +3 -1
- notionary/user/schemas.py +3 -1
- notionary/user/service.py +6 -2
- notionary/utils/decorators.py +13 -9
- notionary/utils/fuzzy.py +6 -2
- notionary/utils/mixins/logging.py +3 -1
- notionary/utils/pagination.py +14 -4
- notionary/workspace/__init__.py +6 -2
- notionary/workspace/query/__init__.py +2 -1
- notionary/workspace/query/service.py +42 -13
- notionary/workspace/service.py +74 -46
- {notionary-0.3.1.dist-info → notionary-0.4.1.dist-info}/METADATA +1 -1
- notionary-0.4.1.dist-info/RECORD +236 -0
- notionary/file_upload/models.py +0 -69
- notionary/page/blocks/client.py +0 -1
- notionary/page/content/syntax/__init__.py +0 -4
- notionary/page/content/syntax/models.py +0 -66
- notionary/page/content/syntax/registry.py +0 -393
- notionary/page/page_context.py +0 -50
- notionary/shared/models/cover.py +0 -20
- notionary-0.3.1.dist-info/RECORD +0 -211
- /notionary/page/content/syntax/{grammar.py → definition/grammar.py} +0 -0
- {notionary-0.3.1.dist-info → notionary-0.4.1.dist-info}/WHEEL +0 -0
- {notionary-0.3.1.dist-info → notionary-0.4.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from enum import StrEnum
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Literal, TypeVar
|
|
3
3
|
|
|
4
|
-
from pydantic import BaseModel, Field
|
|
4
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
5
5
|
|
|
6
6
|
from notionary.shared.properties.type import PropertyType
|
|
7
7
|
from notionary.shared.typings import JsonDict
|
|
@@ -126,109 +126,11 @@ class DataSourceStatusGroup(BaseModel):
|
|
|
126
126
|
option_ids: list[str]
|
|
127
127
|
|
|
128
128
|
|
|
129
|
-
# ============================================================================
|
|
130
|
-
# Config Models
|
|
131
|
-
# ============================================================================
|
|
132
|
-
|
|
133
|
-
|
|
134
129
|
class DataSourceStatusConfig(BaseModel):
|
|
135
130
|
options: list[DataSourcePropertyOption] = Field(default_factory=list)
|
|
136
131
|
groups: list[DataSourceStatusGroup] = Field(default_factory=list)
|
|
137
132
|
|
|
138
133
|
|
|
139
|
-
class DataSourceSelectConfig(BaseModel):
|
|
140
|
-
options: list[DataSourcePropertyOption] = Field(default_factory=list)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
class DataSourceMultiSelectConfig(BaseModel):
|
|
144
|
-
options: list[DataSourcePropertyOption] = Field(default_factory=list)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
class DataSourceRelationConfig(BaseModel):
|
|
148
|
-
data_source_id: str
|
|
149
|
-
type: RelationType = RelationType.SINGLE_PROPERTY
|
|
150
|
-
single_property: JsonDict = Field(default_factory=dict)
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
class DataSourceNumberConfig(BaseModel):
|
|
154
|
-
format: NumberFormat
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
class DataSourceFormulaConfig(BaseModel):
|
|
158
|
-
expression: str
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
class DataSourceUniqueIdConfig(BaseModel):
|
|
162
|
-
prefix: str | None = None
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
class DataSourceRollupConfig(BaseModel):
|
|
166
|
-
function: RollupFunction
|
|
167
|
-
relation_property_id: str
|
|
168
|
-
relation_property_name: str
|
|
169
|
-
rollup_property_id: str
|
|
170
|
-
rollup_property_name: str
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
class DataSourceDateConfig(BaseModel): ...
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
class DataSourceCreatedTimeConfig(BaseModel): ...
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
class DataSourceCreatedByConfig(BaseModel): ...
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
class DataSourceLastEditedTimeConfig(BaseModel): ...
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
class DataSourceLastEditedByConfig(BaseModel): ...
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
class DataSourceLastVisitedTimeConfig(BaseModel): ...
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
class DataSourceTitleConfig(BaseModel): ...
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
class DataSourceRichTextConfig(BaseModel): ...
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
class DataSourceURLConfig(BaseModel): ...
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
class DataSourcePeopleConfig(BaseModel): ...
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
class DataSourceCheckboxConfig(BaseModel): ...
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
class DataSourceEmailConfig(BaseModel): ...
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
class DataSourcePhoneNumberConfig(BaseModel): ...
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
class DataSourceFilesConfig(BaseModel): ...
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
class DataSourceButtonConfig(BaseModel): ...
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
class DataSourceLocationConfig(BaseModel): ...
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
class DataSourceVerificationConfig(BaseModel): ...
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
class DataSourcePlaceConfig(BaseModel): ...
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
# ============================================================================
|
|
228
|
-
# Property Models
|
|
229
|
-
# ============================================================================
|
|
230
|
-
|
|
231
|
-
|
|
232
134
|
class DataSourceStatusProperty(DataSourceProperty):
|
|
233
135
|
type: Literal[PropertyType.STATUS] = PropertyType.STATUS
|
|
234
136
|
status: DataSourceStatusConfig = Field(default_factory=DataSourceStatusConfig)
|
|
@@ -242,6 +144,10 @@ class DataSourceStatusProperty(DataSourceProperty):
|
|
|
242
144
|
return [group.name for group in self.status.groups]
|
|
243
145
|
|
|
244
146
|
|
|
147
|
+
class DataSourceSelectConfig(BaseModel):
|
|
148
|
+
options: list[DataSourcePropertyOption] = Field(default_factory=list)
|
|
149
|
+
|
|
150
|
+
|
|
245
151
|
class DataSourceSelectProperty(DataSourceProperty):
|
|
246
152
|
type: Literal[PropertyType.SELECT] = PropertyType.SELECT
|
|
247
153
|
select: DataSourceSelectConfig = Field(default_factory=DataSourceSelectConfig)
|
|
@@ -251,15 +157,28 @@ class DataSourceSelectProperty(DataSourceProperty):
|
|
|
251
157
|
return [option.name for option in self.select.options]
|
|
252
158
|
|
|
253
159
|
|
|
160
|
+
class DataSourceMultiSelectConfig(BaseModel):
|
|
161
|
+
options: list[DataSourcePropertyOption] = Field(default_factory=list)
|
|
162
|
+
|
|
163
|
+
|
|
254
164
|
class DataSourceMultiSelectProperty(DataSourceProperty):
|
|
255
165
|
type: Literal[PropertyType.MULTI_SELECT] = PropertyType.MULTI_SELECT
|
|
256
|
-
multi_select: DataSourceMultiSelectConfig = Field(
|
|
166
|
+
multi_select: DataSourceMultiSelectConfig = Field(
|
|
167
|
+
default_factory=DataSourceMultiSelectConfig
|
|
168
|
+
)
|
|
257
169
|
|
|
258
170
|
@property
|
|
259
171
|
def option_names(self) -> list[str]:
|
|
260
172
|
return [option.name for option in self.multi_select.options]
|
|
261
173
|
|
|
262
174
|
|
|
175
|
+
# https://developers.notion.com/reference/property-object
|
|
176
|
+
class DataSourceRelationConfig(BaseModel):
|
|
177
|
+
data_source_id: str | None = None
|
|
178
|
+
type: RelationType = RelationType.SINGLE_PROPERTY
|
|
179
|
+
single_property: JsonDict = Field(default_factory=dict)
|
|
180
|
+
|
|
181
|
+
|
|
263
182
|
class DataSourceRelationProperty(DataSourceProperty):
|
|
264
183
|
type: Literal[PropertyType.RELATION] = PropertyType.RELATION
|
|
265
184
|
relation: DataSourceRelationConfig = Field(default_factory=DataSourceRelationConfig)
|
|
@@ -269,29 +188,65 @@ class DataSourceRelationProperty(DataSourceProperty):
|
|
|
269
188
|
return self.relation.data_source_id
|
|
270
189
|
|
|
271
190
|
|
|
191
|
+
class DataSourceDateConfig(BaseModel): ...
|
|
192
|
+
|
|
193
|
+
|
|
272
194
|
class DataSourceDateProperty(DataSourceProperty):
|
|
273
195
|
type: Literal[PropertyType.DATE] = PropertyType.DATE
|
|
274
196
|
date: DataSourceDateConfig = Field(default_factory=DataSourceDateConfig)
|
|
275
197
|
|
|
276
198
|
|
|
199
|
+
class DataSourceCreatedTimeConfig(BaseModel): ...
|
|
200
|
+
|
|
201
|
+
|
|
277
202
|
class DataSourceCreatedTimeProperty(DataSourceProperty):
|
|
278
203
|
type: Literal[PropertyType.CREATED_TIME] = PropertyType.CREATED_TIME
|
|
279
|
-
created_time: DataSourceCreatedTimeConfig = Field(
|
|
204
|
+
created_time: DataSourceCreatedTimeConfig = Field(
|
|
205
|
+
default_factory=DataSourceCreatedTimeConfig
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class DataSourceCreatedByConfig(BaseModel): ...
|
|
280
210
|
|
|
281
211
|
|
|
282
212
|
class DataSourceCreatedByProperty(DataSourceProperty):
|
|
283
213
|
type: Literal[PropertyType.CREATED_BY] = PropertyType.CREATED_BY
|
|
284
|
-
created_by: DataSourceCreatedByConfig = Field(
|
|
214
|
+
created_by: DataSourceCreatedByConfig = Field(
|
|
215
|
+
default_factory=DataSourceCreatedByConfig
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class DataSourceLastEditedTimeConfig(BaseModel): ...
|
|
285
220
|
|
|
286
221
|
|
|
287
222
|
class DataSourceLastEditedTimeProperty(DataSourceProperty):
|
|
288
223
|
type: Literal[PropertyType.LAST_EDITED_TIME] = PropertyType.LAST_EDITED_TIME
|
|
289
|
-
last_edited_time: DataSourceLastEditedTimeConfig = Field(
|
|
224
|
+
last_edited_time: DataSourceLastEditedTimeConfig = Field(
|
|
225
|
+
default_factory=DataSourceLastEditedTimeConfig
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
class DataSourceLastEditedByConfig(BaseModel): ...
|
|
290
230
|
|
|
291
231
|
|
|
292
232
|
class DataSourceLastEditedByProperty(DataSourceProperty):
|
|
293
233
|
type: Literal[PropertyType.LAST_EDITED_BY] = PropertyType.LAST_EDITED_BY
|
|
294
|
-
last_edited_by: DataSourceLastEditedByConfig = Field(
|
|
234
|
+
last_edited_by: DataSourceLastEditedByConfig = Field(
|
|
235
|
+
default_factory=DataSourceLastEditedByConfig
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class DataSourceLastVisitedTimeConfig(BaseModel): ...
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
class DataSourceLastVisitedTimeProperty(DataSourceProperty):
|
|
243
|
+
type: Literal[PropertyType.LAST_VISITED_TIME] = PropertyType.LAST_VISITED_TIME
|
|
244
|
+
last_visited_time: DataSourceLastVisitedTimeConfig = Field(
|
|
245
|
+
default_factory=DataSourceLastVisitedTimeConfig
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class DataSourceTitleConfig(BaseModel): ...
|
|
295
250
|
|
|
296
251
|
|
|
297
252
|
class DataSourceTitleProperty(DataSourceProperty):
|
|
@@ -299,9 +254,17 @@ class DataSourceTitleProperty(DataSourceProperty):
|
|
|
299
254
|
title: DataSourceTitleConfig = Field(default_factory=DataSourceTitleConfig)
|
|
300
255
|
|
|
301
256
|
|
|
257
|
+
class DataSourceRichTextConfig(BaseModel): ...
|
|
258
|
+
|
|
259
|
+
|
|
302
260
|
class DataSourceRichTextProperty(DataSourceProperty):
|
|
303
261
|
type: Literal[PropertyType.RICH_TEXT] = PropertyType.RICH_TEXT
|
|
304
|
-
rich_text: DataSourceRichTextConfig = Field(
|
|
262
|
+
rich_text: DataSourceRichTextConfig = Field(
|
|
263
|
+
default_factory=DataSourceRichTextConfig
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class DataSourceURLConfig(BaseModel): ...
|
|
305
268
|
|
|
306
269
|
|
|
307
270
|
class DataSourceURLProperty(DataSourceProperty):
|
|
@@ -309,11 +272,18 @@ class DataSourceURLProperty(DataSourceProperty):
|
|
|
309
272
|
url: DataSourceURLConfig = Field(default_factory=DataSourceURLConfig)
|
|
310
273
|
|
|
311
274
|
|
|
275
|
+
class DataSourcePeopleConfig(BaseModel): ...
|
|
276
|
+
|
|
277
|
+
|
|
312
278
|
class DataSourcePeopleProperty(DataSourceProperty):
|
|
313
279
|
type: Literal[PropertyType.PEOPLE] = PropertyType.PEOPLE
|
|
314
280
|
people: DataSourcePeopleConfig = Field(default_factory=DataSourcePeopleConfig)
|
|
315
281
|
|
|
316
282
|
|
|
283
|
+
class DataSourceNumberConfig(BaseModel):
|
|
284
|
+
format: NumberFormat
|
|
285
|
+
|
|
286
|
+
|
|
317
287
|
class DataSourceNumberProperty(DataSourceProperty):
|
|
318
288
|
type: Literal[PropertyType.NUMBER] = PropertyType.NUMBER
|
|
319
289
|
number: DataSourceNumberConfig
|
|
@@ -323,19 +293,33 @@ class DataSourceNumberProperty(DataSourceProperty):
|
|
|
323
293
|
return self.number.format
|
|
324
294
|
|
|
325
295
|
|
|
296
|
+
class DataSourceCheckboxConfig(BaseModel): ...
|
|
297
|
+
|
|
298
|
+
|
|
326
299
|
class DataSourceCheckboxProperty(DataSourceProperty):
|
|
327
300
|
type: Literal[PropertyType.CHECKBOX] = PropertyType.CHECKBOX
|
|
328
301
|
checkbox: DataSourceCheckboxConfig = Field(default_factory=DataSourceCheckboxConfig)
|
|
329
302
|
|
|
330
303
|
|
|
304
|
+
class DataSourceEmailConfig(BaseModel): ...
|
|
305
|
+
|
|
306
|
+
|
|
331
307
|
class DataSourceEmailProperty(DataSourceProperty):
|
|
332
308
|
type: Literal[PropertyType.EMAIL] = PropertyType.EMAIL
|
|
333
309
|
email: DataSourceEmailConfig = Field(default_factory=DataSourceEmailConfig)
|
|
334
310
|
|
|
335
311
|
|
|
312
|
+
class DataSourcePhoneNumberConfig(BaseModel): ...
|
|
313
|
+
|
|
314
|
+
|
|
336
315
|
class DataSourcePhoneNumberProperty(DataSourceProperty):
|
|
337
316
|
type: Literal[PropertyType.PHONE_NUMBER] = PropertyType.PHONE_NUMBER
|
|
338
|
-
phone_number: DataSourcePhoneNumberConfig = Field(
|
|
317
|
+
phone_number: DataSourcePhoneNumberConfig = Field(
|
|
318
|
+
default_factory=DataSourcePhoneNumberConfig
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
class DataSourceFilesConfig(BaseModel): ...
|
|
339
323
|
|
|
340
324
|
|
|
341
325
|
class DataSourceFilesProperty(DataSourceProperty):
|
|
@@ -343,6 +327,10 @@ class DataSourceFilesProperty(DataSourceProperty):
|
|
|
343
327
|
files: DataSourceFilesConfig = Field(default_factory=DataSourceFilesConfig)
|
|
344
328
|
|
|
345
329
|
|
|
330
|
+
class DataSourceFormulaConfig(BaseModel):
|
|
331
|
+
expression: str
|
|
332
|
+
|
|
333
|
+
|
|
346
334
|
class DataSourceFormulaProperty(DataSourceProperty):
|
|
347
335
|
type: Literal[PropertyType.FORMULA] = PropertyType.FORMULA
|
|
348
336
|
formula: DataSourceFormulaConfig
|
|
@@ -352,6 +340,14 @@ class DataSourceFormulaProperty(DataSourceProperty):
|
|
|
352
340
|
return self.formula.expression
|
|
353
341
|
|
|
354
342
|
|
|
343
|
+
class DataSourceRollupConfig(BaseModel):
|
|
344
|
+
function: RollupFunction
|
|
345
|
+
relation_property_id: str
|
|
346
|
+
relation_property_name: str
|
|
347
|
+
rollup_property_id: str
|
|
348
|
+
rollup_property_name: str
|
|
349
|
+
|
|
350
|
+
|
|
355
351
|
class DataSourceRollupProperty(DataSourceProperty):
|
|
356
352
|
type: Literal[PropertyType.ROLLUP] = PropertyType.ROLLUP
|
|
357
353
|
rollup: DataSourceRollupConfig
|
|
@@ -361,20 +357,60 @@ class DataSourceRollupProperty(DataSourceProperty):
|
|
|
361
357
|
return self.rollup.function
|
|
362
358
|
|
|
363
359
|
|
|
360
|
+
class DataSourceUniqueIdConfig(BaseModel):
|
|
361
|
+
prefix: str | None = None
|
|
362
|
+
|
|
363
|
+
|
|
364
364
|
class DataSourceUniqueIdProperty(DataSourceProperty):
|
|
365
365
|
type: Literal[PropertyType.UNIQUE_ID] = PropertyType.UNIQUE_ID
|
|
366
|
-
unique_id: DataSourceUniqueIdConfig = Field(
|
|
366
|
+
unique_id: DataSourceUniqueIdConfig = Field(
|
|
367
|
+
default_factory=DataSourceUniqueIdConfig
|
|
368
|
+
)
|
|
367
369
|
|
|
368
370
|
@property
|
|
369
371
|
def prefix(self) -> str | None:
|
|
370
372
|
return self.unique_id.prefix
|
|
371
373
|
|
|
372
374
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
375
|
+
class DataSourceButtonConfig(BaseModel): ...
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
class DataSourceButtonProperty(DataSourceProperty):
|
|
379
|
+
type: Literal[PropertyType.BUTTON] = PropertyType.BUTTON
|
|
380
|
+
button: DataSourceButtonConfig = Field(default_factory=DataSourceButtonConfig)
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
class DataSourceLocationConfig(BaseModel): ...
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
class DataSourceLocationProperty(DataSourceProperty):
|
|
387
|
+
type: Literal[PropertyType.LOCATION] = PropertyType.LOCATION
|
|
388
|
+
location: DataSourceLocationConfig = Field(default_factory=DataSourceLocationConfig)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
class DataSourcePlaceConfig(BaseModel): ...
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
class DataSourcePlaceProperty(DataSourceProperty):
|
|
395
|
+
type: Literal[PropertyType.PLACE] = PropertyType.PLACE
|
|
396
|
+
place: DataSourcePlaceConfig = Field(default_factory=DataSourcePlaceConfig)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
class DataSourceVerificationConfig(BaseModel): ...
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
class DataSourceVerificationProperty(DataSourceProperty):
|
|
403
|
+
type: Literal[PropertyType.VERIFICATION] = PropertyType.VERIFICATION
|
|
404
|
+
verification: DataSourceVerificationConfig = Field(
|
|
405
|
+
default_factory=DataSourceVerificationConfig
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
class DataSourceUnknownProperty(BaseModel):
|
|
410
|
+
model_config = ConfigDict(extra="allow")
|
|
411
|
+
|
|
376
412
|
|
|
377
|
-
|
|
413
|
+
type AnyDataSourceProperty = (
|
|
378
414
|
DataSourceStatusProperty
|
|
379
415
|
| DataSourceSelectProperty
|
|
380
416
|
| DataSourceMultiSelectProperty
|
|
@@ -384,6 +420,7 @@ DiscriminatedDataSourceProperty = Annotated[
|
|
|
384
420
|
| DataSourceCreatedByProperty
|
|
385
421
|
| DataSourceLastEditedTimeProperty
|
|
386
422
|
| DataSourceLastEditedByProperty
|
|
423
|
+
| DataSourceLastVisitedTimeProperty
|
|
387
424
|
| DataSourceTitleProperty
|
|
388
425
|
| DataSourceRichTextProperty
|
|
389
426
|
| DataSourceURLProperty
|
|
@@ -395,8 +432,12 @@ DiscriminatedDataSourceProperty = Annotated[
|
|
|
395
432
|
| DataSourceFilesProperty
|
|
396
433
|
| DataSourceFormulaProperty
|
|
397
434
|
| DataSourceRollupProperty
|
|
398
|
-
| DataSourceUniqueIdProperty
|
|
399
|
-
|
|
400
|
-
|
|
435
|
+
| DataSourceUniqueIdProperty
|
|
436
|
+
| DataSourceButtonProperty
|
|
437
|
+
| DataSourceLocationProperty
|
|
438
|
+
| DataSourcePlaceProperty
|
|
439
|
+
| DataSourceVerificationProperty
|
|
440
|
+
| DataSourceUnknownProperty
|
|
441
|
+
)
|
|
401
442
|
|
|
402
443
|
DataSourcePropertyT = TypeVar("DataSourcePropertyT", bound=DataSourceProperty)
|
|
@@ -160,7 +160,9 @@ class DataSourceQueryBuilder:
|
|
|
160
160
|
def people_is_empty(self) -> Self:
|
|
161
161
|
return self._add_filter(ArrayOperator.IS_EMPTY, None)
|
|
162
162
|
|
|
163
|
-
def order_by(
|
|
163
|
+
def order_by(
|
|
164
|
+
self, property_name: str, direction: SortDirection = SortDirection.ASCENDING
|
|
165
|
+
) -> Self:
|
|
164
166
|
self._ensure_property_exists(property_name)
|
|
165
167
|
sort = PropertySort(property=property_name, direction=direction)
|
|
166
168
|
self._sorts.append(sort)
|
|
@@ -178,7 +180,9 @@ class DataSourceQueryBuilder:
|
|
|
178
180
|
def order_by_created_time_descending(self) -> Self:
|
|
179
181
|
return self._order_by_created_time(SortDirection.DESCENDING)
|
|
180
182
|
|
|
181
|
-
def _order_by_created_time(
|
|
183
|
+
def _order_by_created_time(
|
|
184
|
+
self, direction: SortDirection = SortDirection.DESCENDING
|
|
185
|
+
) -> Self:
|
|
182
186
|
sort = TimestampSort(timestamp=TimestampType.CREATED_TIME, direction=direction)
|
|
183
187
|
self._sorts.append(sort)
|
|
184
188
|
return self
|
|
@@ -189,8 +193,12 @@ class DataSourceQueryBuilder:
|
|
|
189
193
|
def order_by_last_edited_time_descending(self) -> Self:
|
|
190
194
|
return self._order_by_last_edited_time(SortDirection.DESCENDING)
|
|
191
195
|
|
|
192
|
-
def _order_by_last_edited_time(
|
|
193
|
-
|
|
196
|
+
def _order_by_last_edited_time(
|
|
197
|
+
self, direction: SortDirection = SortDirection.DESCENDING
|
|
198
|
+
) -> Self:
|
|
199
|
+
sort = TimestampSort(
|
|
200
|
+
timestamp=TimestampType.LAST_EDITED_TIME, direction=direction
|
|
201
|
+
)
|
|
194
202
|
self._sorts.append(sort)
|
|
195
203
|
return self
|
|
196
204
|
|
|
@@ -211,7 +219,10 @@ class DataSourceQueryBuilder:
|
|
|
211
219
|
notion_filter = self._create_notion_filter_if_needed()
|
|
212
220
|
sorts = self._create_sorts_if_needed()
|
|
213
221
|
return DataSourceQueryParams(
|
|
214
|
-
filter=notion_filter,
|
|
222
|
+
filter=notion_filter,
|
|
223
|
+
sorts=sorts,
|
|
224
|
+
page_size=self._page_size,
|
|
225
|
+
total_results_limit=self._total_results_limit,
|
|
215
226
|
)
|
|
216
227
|
|
|
217
228
|
def _select_property_without_negation(self, property_name: str) -> None:
|
|
@@ -264,7 +275,9 @@ class DataSourceQueryBuilder:
|
|
|
264
275
|
def _has_no_filters(self) -> bool:
|
|
265
276
|
return not self._filters
|
|
266
277
|
|
|
267
|
-
def _is_regular_filter_condition(
|
|
278
|
+
def _is_regular_filter_condition(
|
|
279
|
+
self, filter_item: InternalFilterCondition
|
|
280
|
+
) -> bool:
|
|
268
281
|
return isinstance(filter_item, FilterCondition)
|
|
269
282
|
|
|
270
283
|
def _finalize_current_or_group(self) -> None:
|
|
@@ -284,7 +297,11 @@ class DataSourceQueryBuilder:
|
|
|
284
297
|
|
|
285
298
|
def _add_filter(
|
|
286
299
|
self,
|
|
287
|
-
operator: StringOperator
|
|
300
|
+
operator: StringOperator
|
|
301
|
+
| NumberOperator
|
|
302
|
+
| BooleanOperator
|
|
303
|
+
| DateOperator
|
|
304
|
+
| ArrayOperator,
|
|
288
305
|
value: str | int | float | list[str | int | float] | None,
|
|
289
306
|
) -> Self:
|
|
290
307
|
self._ensure_property_is_selected()
|
|
@@ -301,7 +318,9 @@ class DataSourceQueryBuilder:
|
|
|
301
318
|
|
|
302
319
|
property_obj = self._properties.get(self._current_property)
|
|
303
320
|
if property_obj:
|
|
304
|
-
self._query_validator.validate_operator_for_property(
|
|
321
|
+
self._query_validator.validate_operator_for_property(
|
|
322
|
+
self._current_property, property_obj, operator
|
|
323
|
+
)
|
|
305
324
|
return self
|
|
306
325
|
|
|
307
326
|
def _ensure_property_is_selected(self) -> None:
|
|
@@ -313,8 +332,14 @@ class DataSourceQueryBuilder:
|
|
|
313
332
|
|
|
314
333
|
def _apply_negation_if_needed(
|
|
315
334
|
self,
|
|
316
|
-
operator: StringOperator
|
|
317
|
-
|
|
335
|
+
operator: StringOperator
|
|
336
|
+
| NumberOperator
|
|
337
|
+
| BooleanOperator
|
|
338
|
+
| DateOperator
|
|
339
|
+
| ArrayOperator,
|
|
340
|
+
) -> (
|
|
341
|
+
StringOperator | NumberOperator | BooleanOperator | DateOperator | ArrayOperator
|
|
342
|
+
):
|
|
318
343
|
if not self._negate_next:
|
|
319
344
|
return operator
|
|
320
345
|
|
|
@@ -324,7 +349,11 @@ class DataSourceQueryBuilder:
|
|
|
324
349
|
|
|
325
350
|
def _create_filter_condition(
|
|
326
351
|
self,
|
|
327
|
-
operator: StringOperator
|
|
352
|
+
operator: StringOperator
|
|
353
|
+
| NumberOperator
|
|
354
|
+
| BooleanOperator
|
|
355
|
+
| DateOperator
|
|
356
|
+
| ArrayOperator,
|
|
328
357
|
value: str | int | float | list[str | int | float] | None,
|
|
329
358
|
) -> FilterCondition:
|
|
330
359
|
field_type = self._determine_field_type_from_operator(operator)
|
|
@@ -372,13 +401,17 @@ class DataSourceQueryBuilder:
|
|
|
372
401
|
property_filters = [self._build_filter(f) for f in self._filters]
|
|
373
402
|
return CompoundFilter(operator=LogicalOperator.AND, filters=property_filters)
|
|
374
403
|
|
|
375
|
-
def _build_filter(
|
|
404
|
+
def _build_filter(
|
|
405
|
+
self, condition: InternalFilterCondition
|
|
406
|
+
) -> PropertyFilter | CompoundFilter:
|
|
376
407
|
if isinstance(condition, OrGroupMarker):
|
|
377
408
|
return self._build_or_compound_filter(condition)
|
|
378
409
|
return self._build_property_filter(condition)
|
|
379
410
|
|
|
380
411
|
def _build_or_compound_filter(self, or_marker: OrGroupMarker) -> CompoundFilter:
|
|
381
|
-
property_filters = [
|
|
412
|
+
property_filters = [
|
|
413
|
+
self._build_property_filter(c) for c in or_marker.conditions
|
|
414
|
+
]
|
|
382
415
|
return CompoundFilter(operator=LogicalOperator.OR, filters=property_filters)
|
|
383
416
|
|
|
384
417
|
def _build_property_filter(self, condition: FilterCondition) -> PropertyFilter:
|
|
@@ -398,8 +431,14 @@ class DataSourceQueryBuilder:
|
|
|
398
431
|
|
|
399
432
|
def _negate_operator(
|
|
400
433
|
self,
|
|
401
|
-
operator: StringOperator
|
|
402
|
-
|
|
434
|
+
operator: StringOperator
|
|
435
|
+
| NumberOperator
|
|
436
|
+
| BooleanOperator
|
|
437
|
+
| DateOperator
|
|
438
|
+
| ArrayOperator,
|
|
439
|
+
) -> (
|
|
440
|
+
StringOperator | NumberOperator | BooleanOperator | DateOperator | ArrayOperator
|
|
441
|
+
):
|
|
403
442
|
negation_map = {
|
|
404
443
|
StringOperator.EQUALS: StringOperator.DOES_NOT_EQUAL,
|
|
405
444
|
StringOperator.DOES_NOT_EQUAL: StringOperator.EQUALS,
|
|
@@ -436,13 +475,23 @@ class DataSourceQueryBuilder:
|
|
|
436
475
|
|
|
437
476
|
def _raise_operator_cannot_be_negated_error(
|
|
438
477
|
self,
|
|
439
|
-
operator: StringOperator
|
|
478
|
+
operator: StringOperator
|
|
479
|
+
| NumberOperator
|
|
480
|
+
| BooleanOperator
|
|
481
|
+
| DateOperator
|
|
482
|
+
| ArrayOperator,
|
|
440
483
|
) -> None:
|
|
441
|
-
raise ValueError(
|
|
484
|
+
raise ValueError(
|
|
485
|
+
f"Operator '{operator}' cannot be negated. This should not happen - please report this issue."
|
|
486
|
+
)
|
|
442
487
|
|
|
443
488
|
def _determine_field_type_from_operator(
|
|
444
489
|
self,
|
|
445
|
-
operator: StringOperator
|
|
490
|
+
operator: StringOperator
|
|
491
|
+
| NumberOperator
|
|
492
|
+
| BooleanOperator
|
|
493
|
+
| DateOperator
|
|
494
|
+
| ArrayOperator,
|
|
446
495
|
) -> FieldType:
|
|
447
496
|
if isinstance(operator, StringOperator):
|
|
448
497
|
return FieldType.STRING
|
|
@@ -14,7 +14,10 @@ from notionary.utils.mixins.logging import LoggingMixin
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class QueryResolver(LoggingMixin):
|
|
17
|
-
UUID_PATTERN = re.compile(
|
|
17
|
+
UUID_PATTERN = re.compile(
|
|
18
|
+
r"^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$",
|
|
19
|
+
re.IGNORECASE,
|
|
20
|
+
)
|
|
18
21
|
|
|
19
22
|
def __init__(
|
|
20
23
|
self,
|
|
@@ -24,7 +27,9 @@ class QueryResolver(LoggingMixin):
|
|
|
24
27
|
self._user_resolver = user_resolver or PersonNameIdResolver()
|
|
25
28
|
self._page_resolver = page_resolver or PageNameIdResolver()
|
|
26
29
|
|
|
27
|
-
async def resolve_params(
|
|
30
|
+
async def resolve_params(
|
|
31
|
+
self, params: DataSourceQueryParams
|
|
32
|
+
) -> DataSourceQueryParams:
|
|
28
33
|
if not params.filter:
|
|
29
34
|
return params
|
|
30
35
|
|
|
@@ -38,7 +43,9 @@ class QueryResolver(LoggingMixin):
|
|
|
38
43
|
return await self._resolve_compound_filter(filter)
|
|
39
44
|
return filter
|
|
40
45
|
|
|
41
|
-
async def _resolve_compound_filter(
|
|
46
|
+
async def _resolve_compound_filter(
|
|
47
|
+
self, compound: CompoundFilter
|
|
48
|
+
) -> CompoundFilter:
|
|
42
49
|
resolved_filters = []
|
|
43
50
|
for filter in compound.filters:
|
|
44
51
|
resolved = await self._resolve_filter(filter)
|
|
@@ -46,7 +53,9 @@ class QueryResolver(LoggingMixin):
|
|
|
46
53
|
|
|
47
54
|
return CompoundFilter(operator=compound.operator, filters=resolved_filters)
|
|
48
55
|
|
|
49
|
-
async def _resolve_property_filter(
|
|
56
|
+
async def _resolve_property_filter(
|
|
57
|
+
self, prop_filter: PropertyFilter
|
|
58
|
+
) -> PropertyFilter:
|
|
50
59
|
if not self._is_resolvable_property_type(prop_filter.property_type):
|
|
51
60
|
return prop_filter
|
|
52
61
|
|
|
@@ -56,7 +65,9 @@ class QueryResolver(LoggingMixin):
|
|
|
56
65
|
if self._is_uuid(prop_filter.value):
|
|
57
66
|
return prop_filter
|
|
58
67
|
|
|
59
|
-
resolved_value = await self._resolve_value(
|
|
68
|
+
resolved_value = await self._resolve_value(
|
|
69
|
+
prop_filter.value, prop_filter.property_type
|
|
70
|
+
)
|
|
60
71
|
|
|
61
72
|
return PropertyFilter(
|
|
62
73
|
property=prop_filter.property,
|