omniload 0.0.0.dev0__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.
- omniload/conftest.py +72 -0
- omniload/main.py +810 -0
- omniload/src/.gitignore +10 -0
- omniload/src/adjust/__init__.py +108 -0
- omniload/src/adjust/adjust_helpers.py +122 -0
- omniload/src/airtable/__init__.py +84 -0
- omniload/src/allium/__init__.py +128 -0
- omniload/src/anthropic/__init__.py +277 -0
- omniload/src/anthropic/helpers.py +525 -0
- omniload/src/applovin/__init__.py +316 -0
- omniload/src/applovin_max/__init__.py +117 -0
- omniload/src/appsflyer/__init__.py +325 -0
- omniload/src/appsflyer/client.py +110 -0
- omniload/src/appstore/__init__.py +142 -0
- omniload/src/appstore/client.py +126 -0
- omniload/src/appstore/errors.py +15 -0
- omniload/src/appstore/models.py +117 -0
- omniload/src/appstore/resources.py +179 -0
- omniload/src/arrow/__init__.py +81 -0
- omniload/src/asana_source/__init__.py +281 -0
- omniload/src/asana_source/helpers.py +30 -0
- omniload/src/asana_source/settings.py +158 -0
- omniload/src/attio/__init__.py +102 -0
- omniload/src/attio/helpers.py +65 -0
- omniload/src/blob.py +95 -0
- omniload/src/bruin/__init__.py +76 -0
- omniload/src/chess/__init__.py +180 -0
- omniload/src/chess/helpers.py +35 -0
- omniload/src/chess/settings.py +18 -0
- omniload/src/clickup/__init__.py +85 -0
- omniload/src/clickup/helpers.py +47 -0
- omniload/src/collector/spinner.py +43 -0
- omniload/src/couchbase_source/__init__.py +118 -0
- omniload/src/couchbase_source/helpers.py +135 -0
- omniload/src/cursor/__init__.py +83 -0
- omniload/src/cursor/helpers.py +188 -0
- omniload/src/customer_io/__init__.py +486 -0
- omniload/src/customer_io/helpers.py +530 -0
- omniload/src/destinations.py +982 -0
- omniload/src/docebo/__init__.py +589 -0
- omniload/src/docebo/client.py +435 -0
- omniload/src/docebo/helpers.py +97 -0
- omniload/src/dune/__init__.py +104 -0
- omniload/src/dune/helpers.py +108 -0
- omniload/src/dynamodb/__init__.py +86 -0
- omniload/src/elasticsearch/__init__.py +80 -0
- omniload/src/elasticsearch/helpers.py +141 -0
- omniload/src/errors.py +26 -0
- omniload/src/facebook_ads/__init__.py +403 -0
- omniload/src/facebook_ads/exceptions.py +19 -0
- omniload/src/facebook_ads/helpers.py +296 -0
- omniload/src/facebook_ads/settings.py +224 -0
- omniload/src/facebook_ads/utils.py +53 -0
- omniload/src/factory.py +305 -0
- omniload/src/filesystem/__init__.py +133 -0
- omniload/src/filesystem/helpers.py +114 -0
- omniload/src/filesystem/readers.py +187 -0
- omniload/src/filters.py +62 -0
- omniload/src/fireflies/__init__.py +151 -0
- omniload/src/fireflies/helpers.py +753 -0
- omniload/src/fluxx/__init__.py +10013 -0
- omniload/src/fluxx/helpers.py +233 -0
- omniload/src/frankfurter/__init__.py +157 -0
- omniload/src/frankfurter/helpers.py +48 -0
- omniload/src/freshdesk/__init__.py +103 -0
- omniload/src/freshdesk/freshdesk_client.py +151 -0
- omniload/src/freshdesk/settings.py +23 -0
- omniload/src/fundraiseup/__init__.py +95 -0
- omniload/src/fundraiseup/client.py +81 -0
- omniload/src/github/__init__.py +202 -0
- omniload/src/github/helpers.py +207 -0
- omniload/src/github/queries.py +129 -0
- omniload/src/github/settings.py +24 -0
- omniload/src/google_ads/__init__.py +198 -0
- omniload/src/google_ads/field.py +17 -0
- omniload/src/google_ads/metrics.py +254 -0
- omniload/src/google_ads/predicates.py +37 -0
- omniload/src/google_ads/reports.py +411 -0
- omniload/src/google_ads/test_google_ads.py +184 -0
- omniload/src/google_analytics/__init__.py +144 -0
- omniload/src/google_analytics/helpers.py +312 -0
- omniload/src/google_sheets/README.md +95 -0
- omniload/src/google_sheets/__init__.py +166 -0
- omniload/src/google_sheets/helpers/__init__.py +15 -0
- omniload/src/google_sheets/helpers/api_calls.py +160 -0
- omniload/src/google_sheets/helpers/data_processing.py +316 -0
- omniload/src/gorgias/__init__.py +595 -0
- omniload/src/gorgias/helpers.py +166 -0
- omniload/src/hostaway/__init__.py +302 -0
- omniload/src/hostaway/client.py +288 -0
- omniload/src/http/__init__.py +38 -0
- omniload/src/http/readers.py +146 -0
- omniload/src/http_client.py +24 -0
- omniload/src/hubspot/__init__.py +800 -0
- omniload/src/hubspot/helpers.py +417 -0
- omniload/src/hubspot/settings.py +329 -0
- omniload/src/indeed/__init__.py +153 -0
- omniload/src/indeed/helpers.py +228 -0
- omniload/src/influxdb/__init__.py +46 -0
- omniload/src/influxdb/client.py +34 -0
- omniload/src/intercom/__init__.py +142 -0
- omniload/src/intercom/helpers.py +674 -0
- omniload/src/intercom/settings.py +279 -0
- omniload/src/isoc_pulse/__init__.py +159 -0
- omniload/src/jira_source/__init__.py +377 -0
- omniload/src/jira_source/helpers.py +510 -0
- omniload/src/jira_source/settings.py +184 -0
- omniload/src/kafka/__init__.py +120 -0
- omniload/src/kafka/helpers.py +241 -0
- omniload/src/kinesis/__init__.py +153 -0
- omniload/src/kinesis/helpers.py +96 -0
- omniload/src/klaviyo/__init__.py +237 -0
- omniload/src/klaviyo/client.py +212 -0
- omniload/src/klaviyo/helpers.py +19 -0
- omniload/src/linear/__init__.py +634 -0
- omniload/src/linear/helpers.py +111 -0
- omniload/src/linkedin_ads/__init__.py +266 -0
- omniload/src/linkedin_ads/dimension_time_enum.py +17 -0
- omniload/src/linkedin_ads/helpers.py +246 -0
- omniload/src/loader.py +69 -0
- omniload/src/mailchimp/__init__.py +126 -0
- omniload/src/mailchimp/helpers.py +226 -0
- omniload/src/mailchimp/settings.py +164 -0
- omniload/src/masking.py +344 -0
- omniload/src/mixpanel/__init__.py +62 -0
- omniload/src/mixpanel/client.py +104 -0
- omniload/src/monday/__init__.py +246 -0
- omniload/src/monday/helpers.py +392 -0
- omniload/src/monday/settings.py +325 -0
- omniload/src/mongodb/__init__.py +281 -0
- omniload/src/mongodb/helpers.py +975 -0
- omniload/src/notion/__init__.py +69 -0
- omniload/src/notion/helpers/__init__.py +14 -0
- omniload/src/notion/helpers/client.py +178 -0
- omniload/src/notion/helpers/database.py +92 -0
- omniload/src/notion/settings.py +17 -0
- omniload/src/partition.py +32 -0
- omniload/src/personio/__init__.py +345 -0
- omniload/src/personio/helpers.py +100 -0
- omniload/src/phantombuster/__init__.py +65 -0
- omniload/src/phantombuster/client.py +87 -0
- omniload/src/pinterest/__init__.py +82 -0
- omniload/src/pipedrive/__init__.py +212 -0
- omniload/src/pipedrive/helpers/__init__.py +37 -0
- omniload/src/pipedrive/helpers/custom_fields_munger.py +116 -0
- omniload/src/pipedrive/helpers/pages.py +129 -0
- omniload/src/pipedrive/settings.py +41 -0
- omniload/src/pipedrive/typing.py +17 -0
- omniload/src/plusvibeai/__init__.py +335 -0
- omniload/src/plusvibeai/helpers.py +544 -0
- omniload/src/plusvibeai/settings.py +252 -0
- omniload/src/primer/__init__.py +45 -0
- omniload/src/primer/helpers.py +79 -0
- omniload/src/quickbooks/__init__.py +117 -0
- omniload/src/reddit_ads/__init__.py +183 -0
- omniload/src/reddit_ads/helpers.py +232 -0
- omniload/src/resource.py +40 -0
- omniload/src/revenuecat/__init__.py +83 -0
- omniload/src/revenuecat/helpers.py +237 -0
- omniload/src/salesforce/__init__.py +170 -0
- omniload/src/salesforce/helpers.py +78 -0
- omniload/src/shopify/__init__.py +1953 -0
- omniload/src/shopify/exceptions.py +17 -0
- omniload/src/shopify/helpers.py +202 -0
- omniload/src/shopify/settings.py +19 -0
- omniload/src/slack/__init__.py +290 -0
- omniload/src/slack/helpers.py +218 -0
- omniload/src/slack/settings.py +36 -0
- omniload/src/smartsheets/__init__.py +82 -0
- omniload/src/snapchat_ads/__init__.py +455 -0
- omniload/src/snapchat_ads/client.py +72 -0
- omniload/src/snapchat_ads/helpers.py +630 -0
- omniload/src/snapchat_ads/settings.py +130 -0
- omniload/src/socrata_source/__init__.py +83 -0
- omniload/src/socrata_source/helpers.py +85 -0
- omniload/src/socrata_source/settings.py +8 -0
- omniload/src/solidgate/__init__.py +219 -0
- omniload/src/solidgate/helpers.py +154 -0
- omniload/src/sources.py +5408 -0
- omniload/src/sql_database/__init__.py +0 -0
- omniload/src/sql_database/callbacks.py +66 -0
- omniload/src/stripe_analytics/__init__.py +183 -0
- omniload/src/stripe_analytics/helpers.py +386 -0
- omniload/src/stripe_analytics/settings.py +80 -0
- omniload/src/table_definition.py +15 -0
- omniload/src/testdata/fakebqcredentials.json +14 -0
- omniload/src/tiktok_ads/__init__.py +150 -0
- omniload/src/tiktok_ads/tiktok_helpers.py +130 -0
- omniload/src/time.py +11 -0
- omniload/src/trustpilot/__init__.py +48 -0
- omniload/src/trustpilot/client.py +48 -0
- omniload/src/version.py +6 -0
- omniload/src/wise/__init__.py +68 -0
- omniload/src/wise/client.py +63 -0
- omniload/src/zendesk/__init__.py +480 -0
- omniload/src/zendesk/helpers/__init__.py +39 -0
- omniload/src/zendesk/helpers/api_helpers.py +119 -0
- omniload/src/zendesk/helpers/credentials.py +68 -0
- omniload/src/zendesk/helpers/talk_api.py +132 -0
- omniload/src/zendesk/settings.py +71 -0
- omniload/src/zoom/__init__.py +99 -0
- omniload/src/zoom/helpers.py +102 -0
- omniload/testdata/.gitignore +2 -0
- omniload/testdata/create_replace.csv +21 -0
- omniload/testdata/delete_insert_expected.csv +6 -0
- omniload/testdata/delete_insert_part1.csv +5 -0
- omniload/testdata/delete_insert_part2.csv +6 -0
- omniload/testdata/merge_expected.csv +5 -0
- omniload/testdata/merge_part1.csv +4 -0
- omniload/testdata/merge_part2.csv +5 -0
- omniload/tests/unit/test_smartsheets.py +133 -0
- omniload-0.0.0.dev0.dist-info/METADATA +439 -0
- omniload-0.0.0.dev0.dist-info/RECORD +218 -0
- omniload-0.0.0.dev0.dist-info/WHEEL +4 -0
- omniload-0.0.0.dev0.dist-info/entry_points.txt +2 -0
- omniload-0.0.0.dev0.dist-info/licenses/LICENSE.Apache-2.0 +201 -0
- omniload-0.0.0.dev0.dist-info/licenses/LICENSE.md +21 -0
- omniload-0.0.0.dev0.dist-info/licenses/NOTICE +35 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Copyright 2022-2025 ScaleVector
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""A source that extracts data from Notion API"""
|
|
16
|
+
|
|
17
|
+
from typing import Dict, Iterator, List, Optional
|
|
18
|
+
|
|
19
|
+
import dlt
|
|
20
|
+
from dlt.sources import DltResource
|
|
21
|
+
|
|
22
|
+
from .helpers.client import NotionClient
|
|
23
|
+
from .helpers.database import NotionDatabase
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dlt.source(max_table_nesting=1)
|
|
27
|
+
def notion_databases(
|
|
28
|
+
database_ids: Optional[List[Dict[str, str]]] = None,
|
|
29
|
+
api_key: str = dlt.secrets.value,
|
|
30
|
+
) -> Iterator[DltResource]:
|
|
31
|
+
"""
|
|
32
|
+
Retrieves data from Notion databases.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
database_ids (List[Dict[str, str]], optional): A list of dictionaries
|
|
36
|
+
each containing a database id and a name.
|
|
37
|
+
Defaults to None. If None, the function will generate all databases
|
|
38
|
+
in the workspace that are accessible to the integration.
|
|
39
|
+
api_key (str): The Notion API secret key.
|
|
40
|
+
|
|
41
|
+
Yields:
|
|
42
|
+
DltResource: Data resources from Notion databases.
|
|
43
|
+
"""
|
|
44
|
+
notion_client = NotionClient(api_key)
|
|
45
|
+
|
|
46
|
+
if database_ids is None:
|
|
47
|
+
search_results = notion_client.search(
|
|
48
|
+
filter_criteria={"value": "database", "property": "object"}
|
|
49
|
+
)
|
|
50
|
+
database_ids = [
|
|
51
|
+
{"id": result["id"], "use_name": result["title"][0]["plain_text"]}
|
|
52
|
+
for result in search_results
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
for database in database_ids:
|
|
56
|
+
if "use_name" not in database:
|
|
57
|
+
# Fetch the database details from Notion
|
|
58
|
+
details = notion_client.get_database(database["id"])
|
|
59
|
+
|
|
60
|
+
# Extract the name/title from the details
|
|
61
|
+
database["use_name"] = details["title"][0]["plain_text"]
|
|
62
|
+
|
|
63
|
+
notion_database = NotionDatabase(database["id"], notion_client)
|
|
64
|
+
yield dlt.resource( # type: ignore
|
|
65
|
+
notion_database.query(),
|
|
66
|
+
primary_key="id",
|
|
67
|
+
name=database["use_name"],
|
|
68
|
+
write_disposition="replace",
|
|
69
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Copyright 2022-2025 ScaleVector
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Copyright 2022-2025 ScaleVector
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from typing import Any, Dict, Iterator, Optional
|
|
16
|
+
|
|
17
|
+
from dlt.sources.helpers import requests
|
|
18
|
+
|
|
19
|
+
from ..settings import API_URL
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class NotionClient:
|
|
23
|
+
"""A client to interact with the Notion API.
|
|
24
|
+
|
|
25
|
+
Attributes:
|
|
26
|
+
api_key (str): The Notion API secret key.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__(self, api_key: Optional[str] = None):
|
|
30
|
+
self.api_key = api_key
|
|
31
|
+
|
|
32
|
+
def _create_headers(self) -> Dict[str, str]:
|
|
33
|
+
headers = {
|
|
34
|
+
"accept": "application/json",
|
|
35
|
+
"Notion-Version": "2022-06-28",
|
|
36
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
37
|
+
}
|
|
38
|
+
return headers
|
|
39
|
+
|
|
40
|
+
def _filter_out_none_values(self, dict_in: Dict[str, Any]) -> Dict[str, Any]:
|
|
41
|
+
return {k: v for k, v in dict_in.items() if v is not None}
|
|
42
|
+
|
|
43
|
+
def get_endpoint(
|
|
44
|
+
self, resource: str, resource_id: str, subresource: Optional[str] = None
|
|
45
|
+
) -> str:
|
|
46
|
+
"""Returns the endpoint for a given resource.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
resource (str): The resource to get the endpoint for.
|
|
50
|
+
resource_id (str): The id of the resource.
|
|
51
|
+
subresource (str, optional): The subresource to get the endpoint for.
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
str: The endpoint for the resource.
|
|
55
|
+
"""
|
|
56
|
+
url = f"{API_URL}/{resource}/{resource_id}"
|
|
57
|
+
if subresource:
|
|
58
|
+
url += f"/{subresource}"
|
|
59
|
+
return url
|
|
60
|
+
|
|
61
|
+
def fetch_resource(
|
|
62
|
+
self, resource: str, resource_id: str, subresource: Optional[str] = None
|
|
63
|
+
) -> Any:
|
|
64
|
+
"""Fetches a resource from the Notion API.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
resource (str): The resource to fetch.
|
|
68
|
+
resource_id (str): The id of the resource.
|
|
69
|
+
subresource (str, optional): The subresource to fetch. Defaults to None.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Any: The resource from the Notion API.
|
|
73
|
+
"""
|
|
74
|
+
url = self.get_endpoint(resource, resource_id, subresource)
|
|
75
|
+
headers = self._create_headers()
|
|
76
|
+
response = requests.get(url, headers=headers)
|
|
77
|
+
response.raise_for_status()
|
|
78
|
+
return response.json()
|
|
79
|
+
|
|
80
|
+
def send_payload(
|
|
81
|
+
self,
|
|
82
|
+
resource: str,
|
|
83
|
+
resource_id: str,
|
|
84
|
+
subresource: Optional[str] = None,
|
|
85
|
+
query_params: Optional[Dict[str, Any]] = None,
|
|
86
|
+
payload: Optional[Dict[str, Any]] = None,
|
|
87
|
+
) -> Any:
|
|
88
|
+
"""Sends a payload to the Notion API using the POST method.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
resource (str): The resource to send the payload to.
|
|
92
|
+
resource_id (str): The id of the resource.
|
|
93
|
+
subresource (str, optional): The subresource to send the payload to.
|
|
94
|
+
Defaults to None.
|
|
95
|
+
query_params (Dict[str, Any], optional): The query parameters to send
|
|
96
|
+
with the payload. Defaults to None.
|
|
97
|
+
payload (Dict[str, Any], optional): The payload to send. Defaults to None.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Any: The response from the Notion API.
|
|
101
|
+
|
|
102
|
+
Raises:
|
|
103
|
+
requests.HTTPError: If the response from the Notion API is not 200.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
url = self.get_endpoint(resource, resource_id, subresource)
|
|
107
|
+
headers = self._create_headers()
|
|
108
|
+
|
|
109
|
+
if payload is None:
|
|
110
|
+
payload = {}
|
|
111
|
+
|
|
112
|
+
filtered_payload = self._filter_out_none_values(payload)
|
|
113
|
+
|
|
114
|
+
response = requests.post(
|
|
115
|
+
url, headers=headers, params=query_params, json=filtered_payload
|
|
116
|
+
)
|
|
117
|
+
response.raise_for_status()
|
|
118
|
+
return response.json()
|
|
119
|
+
|
|
120
|
+
def search(
|
|
121
|
+
self,
|
|
122
|
+
query: Optional[str] = None,
|
|
123
|
+
filter_criteria: Optional[Dict[str, Any]] = None,
|
|
124
|
+
sort: Optional[Dict[str, Any]] = None,
|
|
125
|
+
start_cursor: Optional[str] = None,
|
|
126
|
+
page_size: Optional[int] = None,
|
|
127
|
+
) -> Iterator[Dict[str, Any]]:
|
|
128
|
+
"""Searches all parent or child pages and databases that have been
|
|
129
|
+
shared with an integration.
|
|
130
|
+
|
|
131
|
+
Notion API Reference. Search:
|
|
132
|
+
https://developers.notion.com/reference/post-search
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
query (str, optional): The string to search for. Defaults to None.
|
|
136
|
+
filter_criteria (Dict[str, Any], optional): The filter to apply to
|
|
137
|
+
the results.
|
|
138
|
+
sort (Dict[str, Any], optional): The sort to apply to the results.
|
|
139
|
+
start_cursor (str, optional): The cursor to start the query at.
|
|
140
|
+
Defaults to None.
|
|
141
|
+
page_size (int, optional): The number of results to return.
|
|
142
|
+
Defaults to None.
|
|
143
|
+
|
|
144
|
+
Yields:
|
|
145
|
+
Dict[str, Any]: A result from the search.
|
|
146
|
+
"""
|
|
147
|
+
has_more = True
|
|
148
|
+
|
|
149
|
+
while has_more:
|
|
150
|
+
payload = {
|
|
151
|
+
"query": query,
|
|
152
|
+
"sort": sort,
|
|
153
|
+
"filter": filter_criteria,
|
|
154
|
+
"start_cursor": start_cursor,
|
|
155
|
+
"page_size": page_size,
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
filtered_payload = self._filter_out_none_values(payload)
|
|
159
|
+
|
|
160
|
+
response = self.send_payload("search", "", payload=filtered_payload)
|
|
161
|
+
|
|
162
|
+
for result in response.get("results", []):
|
|
163
|
+
yield result
|
|
164
|
+
|
|
165
|
+
next_cursor = response.get("next_cursor")
|
|
166
|
+
has_more = next_cursor is not None
|
|
167
|
+
start_cursor = next_cursor
|
|
168
|
+
|
|
169
|
+
def get_database(self, database_id: str) -> Any:
|
|
170
|
+
"""Fetches the details of a specific database by its ID.
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
database_id (str): The ID of the database to fetch.
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
Any: The details of the database.
|
|
177
|
+
"""
|
|
178
|
+
return self.fetch_resource("databases", database_id)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Copyright 2022-2025 ScaleVector
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from typing import Any, Dict, Iterable, Optional
|
|
16
|
+
|
|
17
|
+
from dlt.common.typing import TDataItem
|
|
18
|
+
|
|
19
|
+
from .client import NotionClient
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class NotionDatabase:
|
|
23
|
+
"""
|
|
24
|
+
A class to represent a Notion database.
|
|
25
|
+
|
|
26
|
+
Attributes:
|
|
27
|
+
database_id (str): The ID of the Notion database.
|
|
28
|
+
notion_client (NotionClient): A client to interact with the Notion API.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, database_id: str, notion_client: NotionClient):
|
|
32
|
+
self.database_id = database_id
|
|
33
|
+
self.notion_client = notion_client
|
|
34
|
+
|
|
35
|
+
def get_structure(self) -> Any:
|
|
36
|
+
"""Retrieves the structure of the database.
|
|
37
|
+
|
|
38
|
+
Notion API Reference. Retrieve a database:
|
|
39
|
+
https://developers.notion.com/reference/retrieve-a-database
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Any: The structure of the database.
|
|
43
|
+
"""
|
|
44
|
+
return self.notion_client.fetch_resource("databases", self.database_id)
|
|
45
|
+
|
|
46
|
+
def query(
|
|
47
|
+
self,
|
|
48
|
+
filter_properties: Optional[Dict[str, Any]] = None,
|
|
49
|
+
filter_criteria: Optional[Dict[str, Any]] = None,
|
|
50
|
+
sorts: Optional[Dict[str, Any]] = None,
|
|
51
|
+
start_cursor: Optional[str] = None,
|
|
52
|
+
page_size: Optional[int] = None,
|
|
53
|
+
) -> Iterable[TDataItem]:
|
|
54
|
+
"""Queries the database for records.
|
|
55
|
+
|
|
56
|
+
Notion API Reference. Query a database:
|
|
57
|
+
https://developers.notion.com/reference/post-database-query
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
filter_properties (Dict[str, Any], optional): A dictionary of
|
|
61
|
+
properties to filter the records by. Defaults to None.
|
|
62
|
+
filter_criteria (Dict[str, Any], optional): A dictionary of filters
|
|
63
|
+
to apply to the records. Defaults to None.
|
|
64
|
+
sorts (Dict[str, Any], optional): A dictionary of sorts to apply
|
|
65
|
+
to the records. Defaults to None.
|
|
66
|
+
start_cursor (str, optional): The cursor to start the query at.
|
|
67
|
+
Defaults to None.
|
|
68
|
+
page_size (int, optional): The number of records to return.
|
|
69
|
+
Defaults to None.
|
|
70
|
+
|
|
71
|
+
Yields:
|
|
72
|
+
List[Dict[str, Any]]: A record from the database.
|
|
73
|
+
"""
|
|
74
|
+
while True:
|
|
75
|
+
payload = {
|
|
76
|
+
"filter": filter_criteria,
|
|
77
|
+
"sorts": sorts,
|
|
78
|
+
"start_cursor": start_cursor,
|
|
79
|
+
"page_size": page_size,
|
|
80
|
+
}
|
|
81
|
+
response = self.notion_client.send_payload(
|
|
82
|
+
"databases",
|
|
83
|
+
self.database_id,
|
|
84
|
+
subresource="query",
|
|
85
|
+
query_params=filter_properties,
|
|
86
|
+
payload=payload,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
yield response.get("results", [])
|
|
90
|
+
if not response.get("has_more"):
|
|
91
|
+
break
|
|
92
|
+
start_cursor = response.get("next_cursor")
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Copyright 2022-2025 ScaleVector
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Notion source settings and constants"""
|
|
16
|
+
|
|
17
|
+
API_URL = "https://api.notion.com/v1"
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from typing import Dict
|
|
2
|
+
|
|
3
|
+
from dlt.common.schema.typing import TColumnSchema
|
|
4
|
+
from dlt.sources import DltResource, DltSource
|
|
5
|
+
|
|
6
|
+
import omniload.src.resource as resource
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def apply_athena_hints(
|
|
10
|
+
source: DltSource | DltResource,
|
|
11
|
+
partition_column: str,
|
|
12
|
+
additional_hints: Dict[str, TColumnSchema] = {},
|
|
13
|
+
) -> None:
|
|
14
|
+
from dlt.destinations.adapters import athena_adapter, athena_partition
|
|
15
|
+
|
|
16
|
+
def _apply_partition_hint(resource: DltResource) -> None:
|
|
17
|
+
columns = resource.columns if resource.columns else {}
|
|
18
|
+
|
|
19
|
+
partition_hint = (
|
|
20
|
+
columns.get(partition_column) # type: ignore
|
|
21
|
+
or additional_hints.get(partition_column)
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
athena_adapter(
|
|
25
|
+
resource,
|
|
26
|
+
athena_partition.day(partition_column)
|
|
27
|
+
if partition_hint
|
|
28
|
+
and partition_hint.get("data_type") in ("timestamp", "date")
|
|
29
|
+
else partition_column,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
resource.for_each(source, _apply_partition_hint)
|