ingestr 0.10.0rc5__tar.gz → 0.10.2__tar.gz

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.

Potentially problematic release.


This version of ingestr might be problematic. Click here for more details.

Files changed (168) hide show
  1. {ingestr-0.10.0rc5 → ingestr-0.10.2}/PKG-INFO +4 -2
  2. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/.vitepress/config.mjs +1 -0
  3. ingestr-0.10.2/docs/media/athena.png +0 -0
  4. ingestr-0.10.2/docs/supported-sources/athena.md +36 -0
  5. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/main.py +20 -3
  6. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/adjust/__init__.py +1 -1
  7. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/destinations.py +61 -1
  8. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/factory.py +2 -0
  9. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/filters.py +0 -2
  10. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/sources.py +11 -6
  11. ingestr-0.10.2/ingestr/src/version.py +1 -0
  12. {ingestr-0.10.0rc5 → ingestr-0.10.2}/package-lock.json +142 -89
  13. {ingestr-0.10.0rc5 → ingestr-0.10.2}/package.json +1 -0
  14. {ingestr-0.10.0rc5 → ingestr-0.10.2}/requirements.txt +3 -2
  15. ingestr-0.10.0rc5/ingestr/src/version.py +0 -1
  16. {ingestr-0.10.0rc5 → ingestr-0.10.2}/.dockerignore +0 -0
  17. {ingestr-0.10.0rc5 → ingestr-0.10.2}/.github/workflows/deploy-docs.yml +0 -0
  18. {ingestr-0.10.0rc5 → ingestr-0.10.2}/.github/workflows/tests.yml +0 -0
  19. {ingestr-0.10.0rc5 → ingestr-0.10.2}/.gitignore +0 -0
  20. {ingestr-0.10.0rc5 → ingestr-0.10.2}/.python-version +0 -0
  21. {ingestr-0.10.0rc5 → ingestr-0.10.2}/.vale.ini +0 -0
  22. {ingestr-0.10.0rc5 → ingestr-0.10.2}/Dockerfile +0 -0
  23. {ingestr-0.10.0rc5 → ingestr-0.10.2}/LICENSE.md +0 -0
  24. {ingestr-0.10.0rc5 → ingestr-0.10.2}/Makefile +0 -0
  25. {ingestr-0.10.0rc5 → ingestr-0.10.2}/README.md +0 -0
  26. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/.vitepress/theme/custom.css +0 -0
  27. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/.vitepress/theme/index.js +0 -0
  28. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/commands/example-uris.md +0 -0
  29. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/commands/ingest.md +0 -0
  30. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/getting-started/core-concepts.md +0 -0
  31. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/getting-started/incremental-loading.md +0 -0
  32. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/getting-started/quickstart.md +0 -0
  33. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/getting-started/telemetry.md +0 -0
  34. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/index.md +0 -0
  35. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/adjust.md +0 -0
  36. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/airtable.md +0 -0
  37. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/appsflyer.md +0 -0
  38. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/bigquery.md +0 -0
  39. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/chess.md +0 -0
  40. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/csv.md +0 -0
  41. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/databricks.md +0 -0
  42. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/duckdb.md +0 -0
  43. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/facebook-ads.md +0 -0
  44. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/gorgias.md +0 -0
  45. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/gsheets.md +0 -0
  46. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/hubspot.md +0 -0
  47. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/kafka.md +0 -0
  48. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/klaviyo.md +0 -0
  49. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/mongodb.md +0 -0
  50. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/mssql.md +0 -0
  51. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/mysql.md +0 -0
  52. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/notion.md +0 -0
  53. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/oracle.md +0 -0
  54. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/postgres.md +0 -0
  55. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/redshift.md +0 -0
  56. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/s3.md +0 -0
  57. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/sap-hana.md +0 -0
  58. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/shopify.md +0 -0
  59. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/slack.md +0 -0
  60. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/snowflake.md +0 -0
  61. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/sqlite.md +0 -0
  62. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/stripe.md +0 -0
  63. {ingestr-0.10.0rc5 → ingestr-0.10.2}/docs/supported-sources/zendesk.md +0 -0
  64. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/.gitignore +0 -0
  65. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/adjust/adjust_helpers.py +0 -0
  66. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/airtable/__init__.py +0 -0
  67. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/appsflyer/_init_.py +0 -0
  68. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/appsflyer/client.py +0 -0
  69. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/arrow/__init__.py +0 -0
  70. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/chess/__init__.py +0 -0
  71. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/chess/helpers.py +0 -0
  72. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/chess/settings.py +0 -0
  73. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/facebook_ads/__init__.py +0 -0
  74. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/facebook_ads/exceptions.py +0 -0
  75. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/facebook_ads/helpers.py +0 -0
  76. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/facebook_ads/settings.py +0 -0
  77. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/filesystem/__init__.py +0 -0
  78. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/filesystem/helpers.py +0 -0
  79. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/filesystem/readers.py +0 -0
  80. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/google_sheets/README.md +0 -0
  81. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/google_sheets/__init__.py +0 -0
  82. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
  83. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
  84. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
  85. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/gorgias/__init__.py +0 -0
  86. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/gorgias/helpers.py +0 -0
  87. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/hubspot/__init__.py +0 -0
  88. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/hubspot/helpers.py +0 -0
  89. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/hubspot/settings.py +0 -0
  90. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/kafka/__init__.py +0 -0
  91. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/kafka/helpers.py +0 -0
  92. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/klaviyo/_init_.py +0 -0
  93. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/klaviyo/client.py +0 -0
  94. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/klaviyo/helpers.py +0 -0
  95. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/mongodb/__init__.py +0 -0
  96. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/mongodb/helpers.py +0 -0
  97. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/notion/__init__.py +0 -0
  98. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/notion/helpers/__init__.py +0 -0
  99. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/notion/helpers/client.py +0 -0
  100. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/notion/helpers/database.py +0 -0
  101. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/notion/settings.py +0 -0
  102. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/shopify/__init__.py +0 -0
  103. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/shopify/exceptions.py +0 -0
  104. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/shopify/helpers.py +0 -0
  105. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/shopify/settings.py +0 -0
  106. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/slack/__init__.py +0 -0
  107. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/slack/helpers.py +0 -0
  108. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/slack/settings.py +0 -0
  109. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/stripe_analytics/__init__.py +0 -0
  110. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/stripe_analytics/helpers.py +0 -0
  111. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/stripe_analytics/settings.py +0 -0
  112. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/table_definition.py +0 -0
  113. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/telemetry/event.py +0 -0
  114. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/testdata/fakebqcredentials.json +0 -0
  115. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/zendesk/__init__.py +0 -0
  116. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/zendesk/helpers/__init__.py +0 -0
  117. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
  118. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/zendesk/helpers/credentials.py +0 -0
  119. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
  120. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/src/zendesk/settings.py +0 -0
  121. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/testdata/.gitignore +0 -0
  122. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/testdata/create_replace.csv +0 -0
  123. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/testdata/delete_insert_expected.csv +0 -0
  124. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/testdata/delete_insert_part1.csv +0 -0
  125. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/testdata/delete_insert_part2.csv +0 -0
  126. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/testdata/merge_expected.csv +0 -0
  127. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/testdata/merge_part1.csv +0 -0
  128. {ingestr-0.10.0rc5 → ingestr-0.10.2}/ingestr/testdata/merge_part2.csv +0 -0
  129. {ingestr-0.10.0rc5 → ingestr-0.10.2}/pyproject.toml +0 -0
  130. {ingestr-0.10.0rc5 → ingestr-0.10.2}/requirements-dev.txt +0 -0
  131. {ingestr-0.10.0rc5 → ingestr-0.10.2}/resources/demo.gif +0 -0
  132. {ingestr-0.10.0rc5 → ingestr-0.10.2}/resources/demo.tape +0 -0
  133. {ingestr-0.10.0rc5 → ingestr-0.10.2}/resources/ingestr.svg +0 -0
  134. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/AMPM.yml +0 -0
  135. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Acronyms.yml +0 -0
  136. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Colons.yml +0 -0
  137. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Contractions.yml +0 -0
  138. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/DateFormat.yml +0 -0
  139. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Ellipses.yml +0 -0
  140. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/EmDash.yml +0 -0
  141. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Exclamation.yml +0 -0
  142. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/FirstPerson.yml +0 -0
  143. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Gender.yml +0 -0
  144. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/GenderBias.yml +0 -0
  145. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/HeadingPunctuation.yml +0 -0
  146. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Headings.yml +0 -0
  147. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Latin.yml +0 -0
  148. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/LyHyphens.yml +0 -0
  149. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/OptionalPlurals.yml +0 -0
  150. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Ordinal.yml +0 -0
  151. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/OxfordComma.yml +0 -0
  152. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Parens.yml +0 -0
  153. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Passive.yml +0 -0
  154. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Periods.yml +0 -0
  155. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Quotes.yml +0 -0
  156. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Ranges.yml +0 -0
  157. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Semicolons.yml +0 -0
  158. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Slang.yml +0 -0
  159. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Spacing.yml +0 -0
  160. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Spelling.yml +0 -0
  161. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Units.yml +0 -0
  162. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/We.yml +0 -0
  163. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/Will.yml +0 -0
  164. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/WordList.yml +0 -0
  165. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/meta.json +0 -0
  166. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/Google/vocab.txt +0 -0
  167. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/bruin/Ingestr.yml +0 -0
  168. {ingestr-0.10.0rc5 → ingestr-0.10.2}/styles/config/vocabularies/bruin/accept.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ingestr
3
- Version: 0.10.0rc5
3
+ Version: 0.10.2
4
4
  Summary: ingestr is a command-line application that ingests data from various sources and stores them in any database.
5
5
  Project-URL: Homepage, https://github.com/bruin-data/ingestr
6
6
  Project-URL: Issues, https://github.com/bruin-data/ingestr/issues
@@ -26,13 +26,15 @@ Requires-Dist: pendulum==3.0.0
26
26
  Requires-Dist: psycopg2-binary==2.9.10
27
27
  Requires-Dist: py-machineid==0.6.0
28
28
  Requires-Dist: pyairtable==2.3.3
29
+ Requires-Dist: pyarrow==18.1.0
30
+ Requires-Dist: pyathena==3.9.0
29
31
  Requires-Dist: pymongo==4.10.1
30
32
  Requires-Dist: pymysql==1.1.1
31
33
  Requires-Dist: pyrate-limiter==3.7.0
32
34
  Requires-Dist: redshift-connector==2.1.3
33
35
  Requires-Dist: rich==13.9.4
34
36
  Requires-Dist: rudder-sdk-python==2.1.4
35
- Requires-Dist: s3fs==2024.9.0
37
+ Requires-Dist: s3fs==2024.10.0
36
38
  Requires-Dist: snowflake-sqlalchemy==1.6.1
37
39
  Requires-Dist: sqlalchemy-bigquery==1.12.0
38
40
  Requires-Dist: sqlalchemy-hana==2.0.0
@@ -57,6 +57,7 @@ export default defineConfig({
57
57
  text: "Databases",
58
58
  collapsed: false,
59
59
  items: [
60
+ { text: "Athena", link: "/supported-sources/athena.md" },
60
61
  { text: "AWS Redshift", link: "/supported-sources/redshift.md" },
61
62
  { text: "Databricks", link: "/supported-sources/databricks.md" },
62
63
  { text: "DuckDB", link: "/supported-sources/duckdb.md" },
Binary file
@@ -0,0 +1,36 @@
1
+ # Athena
2
+ [Athena](https://aws.amazon.com/athena/) is an interactive query service that allows users to analyze data directly in Amazon S3 using standard SQL.
3
+
4
+ The Athena destination stores data as Parquet files in S3 buckets and creates external tables in AWS Glue Catalog.
5
+
6
+ ingestr supports Athena as a destination.
7
+
8
+ ## URI format
9
+ The URI format for Athena is as follows:
10
+
11
+ ```plaintext
12
+ athena://?bucket=<your-destination-bucket> \
13
+ query_results_path=<your-query-results-location> \
14
+ access_key_id=<your-aws-access-key-id> \
15
+ secret_access_key=<your-aws-secret-access-key> \
16
+ region_name=<your-aws-region>
17
+ ```
18
+ URI parameters:
19
+ - `bucket` (required): The name of the bucket where the data will be stored, containing the Parquet files that Athena will work with, e.g. `your_bucket_name` or `s3://your_bucket_name`.
20
+ - `access_key_id` and `secret_access_key` (required): These are AWS credentials that will be used to authenticate with AWS services like S3 and Athena.
21
+ - `region_name` (required): The AWS region of the Athena service and S3 buckets, e.g. `eu-central-1`
22
+ - `query_results_path` (optional): The query location path where the results of Athena queries will be saved, e.g. `dest_path` or `s3://dest_path`. If not provided, it will default to the bucket specified in the `bucket` parameter.
23
+ - `workgroup` (optional): The name of the Athena workgroup, e.g. `my_group`
24
+
25
+ ## Setting up an Athena Integration
26
+ Athena requires a `bucket`, `access_key_id`, `secret_access_key` and `region_name` to access the S3 bucket. Please follow the guide on dltHub to obtain [credentials](https://dlthub.com/docs/dlt-ecosystem/destinations/athena#2-setup-bucket-storage-and-athena-credentials). Once you've completed the guide, you should have all the above-mentioned credentials.
27
+ ```
28
+ ingestr ingest \
29
+ --source-uri "stripe://?api_key=key123" \
30
+ --source-table 'event' \
31
+ --dest-uri "athena://?bucket=bucket_123&access_key_id=access_123&secret_access_key=secret_123&region_name=eu-central-1" \
32
+ --dest-table 'stripe.event'
33
+ ```
34
+ This is a sample command that will copy the data from the Stripe source into Athena.
35
+
36
+ <img alt="athena_img" src="../media/athena.png" />
@@ -348,6 +348,14 @@ def ingest(
348
348
  )
349
349
  raise typer.Abort()
350
350
 
351
+ def run_on_resource(source, executable):
352
+ if hasattr(source, "selected_resources") and source.selected_resources:
353
+ resource_names = list(source.selected_resources.keys())
354
+ for res in resource_names:
355
+ executable(source.resources[res])
356
+ else:
357
+ executable(source)
358
+
351
359
  track(
352
360
  "command_triggered",
353
361
  {
@@ -487,10 +495,20 @@ def ingest(
487
495
  sql_exclude_columns=sql_exclude_columns,
488
496
  )
489
497
 
490
- dlt_source.add_map(cast_set_to_list)
498
+ run_on_resource(dlt_source, lambda x: x.add_map(cast_set_to_list))
499
+
500
+ def col_h(x):
501
+ if column_hints:
502
+ x.apply_hints(columns=column_hints)
503
+
504
+ run_on_resource(dlt_source, col_h)
491
505
 
492
506
  if original_incremental_strategy == IncrementalStrategy.delete_insert:
493
- dlt_source.incremental.primary_key = ()
507
+
508
+ def set_primary_key(x):
509
+ x.incremental.primary_key = ()
510
+
511
+ run_on_resource(dlt_source, set_primary_key)
494
512
 
495
513
  if (
496
514
  factory.destination_scheme in PARQUET_SUPPORTED_DESTINATIONS
@@ -522,7 +540,6 @@ def ingest(
522
540
  loader_file_format=(
523
541
  loader_file_format.value if loader_file_format is not None else None # type: ignore
524
542
  ), # type: ignore
525
- columns=column_hints,
526
543
  )
527
544
 
528
545
  report_errors(run_info)
@@ -82,7 +82,7 @@ def adjust_source(
82
82
  type_hints[metric] = KNOWN_TYPE_HINTS[metric]
83
83
 
84
84
  @dlt.resource(
85
- write_disposition={"disposition": "merge", "strategy": "delete+insert"},
85
+ write_disposition={"disposition": "merge", "strategy": "delete-insert"},
86
86
  merge_key=merge_key,
87
87
  primary_key=dimensions,
88
88
  columns=type_hints,
@@ -5,9 +5,10 @@ import json
5
5
  import os
6
6
  import shutil
7
7
  import tempfile
8
- from urllib.parse import parse_qs, urlparse
8
+ from urllib.parse import parse_qs, quote, urlparse
9
9
 
10
10
  import dlt
11
+ from dlt.common.configuration.specs import AwsCredentials
11
12
 
12
13
 
13
14
  class GenericSqlDestination:
@@ -194,3 +195,62 @@ class CsvDestination(GenericSqlDestination):
194
195
  csv_writer.writerow(json_obj)
195
196
 
196
197
  shutil.rmtree(self.temp_path)
198
+
199
+
200
+ class AthenaDestination:
201
+ def dlt_dest(self, uri: str, **kwargs):
202
+ encoded_uri = quote(uri, safe=":/?&=")
203
+ source_fields = urlparse(encoded_uri)
204
+ source_params = parse_qs(source_fields.query)
205
+
206
+ bucket = source_params.get("bucket", [None])[0]
207
+ if not bucket:
208
+ raise ValueError("A bucket is required to connect to Athena.")
209
+
210
+ if not bucket.startswith("s3://"):
211
+ bucket = f"s3://{bucket}"
212
+
213
+ query_result_path = source_params.get("query_results_path", [None])[0]
214
+ if query_result_path:
215
+ if not query_result_path.startswith("s3://"):
216
+ query_result_path = f"s3://{query_result_path}"
217
+ else:
218
+ query_result_path = bucket
219
+
220
+ access_key_id = source_params.get("access_key_id", [None])[0]
221
+ if not access_key_id:
222
+ raise ValueError("The AWS access_key_id is required to connect to Athena.")
223
+
224
+ secret_access_key = source_params.get("secret_access_key", [None])[0]
225
+ if not secret_access_key:
226
+ raise ValueError("The AWS secret_access_key is required to connect Athena")
227
+
228
+ work_group = source_params.get("workgroup", [None])[0]
229
+
230
+ region_name = source_params.get("region_name", [None])[0]
231
+ if not region_name:
232
+ raise ValueError("The region_name is required to connect to Athena.")
233
+
234
+ os.environ["DESTINATION__BUCKET_URL"] = bucket
235
+ os.environ["DESTINATION__CREDENTIALS__AWS_ACCESS_KEY_ID"] = access_key_id
236
+ os.environ["DESTINATION__CREDENTIALS__AWS_SECRET_ACCESS_KEY"] = (
237
+ secret_access_key
238
+ )
239
+
240
+ credentials = AwsCredentials(
241
+ aws_access_key_id=access_key_id,
242
+ aws_secret_access_key=secret_access_key,
243
+ region_name=region_name,
244
+ )
245
+ return dlt.destinations.athena(
246
+ query_result_bucket=query_result_path,
247
+ athena_work_group=work_group,
248
+ credentials=credentials,
249
+ destination_name=bucket,
250
+ )
251
+
252
+ def dlt_run_params(self, uri: str, table: str, **kwargs) -> dict:
253
+ return {}
254
+
255
+ def post_load(self):
256
+ pass
@@ -4,6 +4,7 @@ from urllib.parse import urlparse
4
4
  from dlt.common.destination import Destination
5
5
 
6
6
  from ingestr.src.destinations import (
7
+ AthenaDestination,
7
8
  BigQueryDestination,
8
9
  CsvDestination,
9
10
  DatabricksDestination,
@@ -159,6 +160,7 @@ class SourceDestinationFactory:
159
160
  "snowflake": SnowflakeDestination(),
160
161
  "synapse": SynapseDestination(),
161
162
  "csv": CsvDestination(),
163
+ "athena": AthenaDestination(),
162
164
  }
163
165
 
164
166
  if self.destination_scheme in match:
@@ -11,8 +11,6 @@ def cast_set_to_list(row):
11
11
 
12
12
 
13
13
  def table_adapter_exclude_columns(cols: list[str]):
14
- print("given cols", cols)
15
-
16
14
  def excluder(table: Table):
17
15
  cols_to_remove = [col for col in table._columns if col.name in cols] # type: ignore
18
16
  for col in cols_to_remove:
@@ -76,14 +76,17 @@ class SqlSource:
76
76
  if kwargs.get("sql_limit"):
77
77
 
78
78
  def query_adapter_callback(query, table):
79
- return query.limit(kwargs.get("sql_limit"))
79
+ query = query.limit(kwargs.get("sql_limit"))
80
+ if kwargs.get("incremental_key"):
81
+ query = query.order_by(kwargs.get("incremental_key"))
82
+ return query
80
83
 
81
84
  def type_adapter_callback(sql_type):
82
85
  if isinstance(sql_type, mysql.SET):
83
86
  return sa.JSON
84
87
  return sql_type
85
88
 
86
- table_instance = self.table_builder(
89
+ builder_res = self.table_builder(
87
90
  credentials=ConnectionStringCredentials(uri),
88
91
  schema=table_fields.dataset,
89
92
  table=table_fields.table,
@@ -98,7 +101,7 @@ class SqlSource:
98
101
  ),
99
102
  )
100
103
 
101
- return table_instance
104
+ return builder_res
102
105
 
103
106
 
104
107
  class ArrowMemoryMappedSource:
@@ -744,7 +747,7 @@ class KafkaSource:
744
747
 
745
748
  class AdjustSource:
746
749
  def handles_incrementality(self) -> bool:
747
- return False
750
+ return True
748
751
 
749
752
  def dlt_source(self, uri: str, table: str, **kwargs):
750
753
  if kwargs.get("incremental_key") and not table.startswith("custom:"):
@@ -806,7 +809,7 @@ class AdjustSource:
806
809
  filters_raw = fields[3]
807
810
  filters = parse_filters(filters_raw)
808
811
 
809
- return adjust_source(
812
+ src = adjust_source(
810
813
  start_date=start_date,
811
814
  end_date=end_date,
812
815
  api_key=api_key[0],
@@ -814,7 +817,9 @@ class AdjustSource:
814
817
  metrics=metrics,
815
818
  merge_key=kwargs.get("merge_key"),
816
819
  filters=filters,
817
- ).with_resources(table)
820
+ )
821
+
822
+ return src.with_resources(table)
818
823
 
819
824
 
820
825
  class AppsflyerSource:
@@ -0,0 +1 @@
1
+ __version__ = "0.10.2"