ingestr 0.13.46__tar.gz → 0.13.48__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 (284) hide show
  1. {ingestr-0.13.46 → ingestr-0.13.48}/PKG-INFO +1 -1
  2. {ingestr-0.13.46 → ingestr-0.13.48}/docs/.vitepress/config.mjs +1 -0
  3. ingestr-0.13.48/docs/supported-sources/frankfurter.md +48 -0
  4. ingestr-0.13.48/docs/supported-sources/s3.md +136 -0
  5. ingestr-0.13.48/docs/supported-sources/solidgate.md +46 -0
  6. ingestr-0.13.48/ingestr/src/buildinfo.py +1 -0
  7. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/factory.py +2 -0
  8. ingestr-0.13.48/ingestr/src/solidgate/__init__.py +97 -0
  9. ingestr-0.13.48/ingestr/src/solidgate/helpers.py +78 -0
  10. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/sources.py +46 -1
  11. ingestr-0.13.46/docs/supported-sources/frankfurter.md +0 -173
  12. ingestr-0.13.46/docs/supported-sources/s3.md +0 -46
  13. ingestr-0.13.46/ingestr/src/buildinfo.py +0 -1
  14. {ingestr-0.13.46 → ingestr-0.13.48}/.dockerignore +0 -0
  15. {ingestr-0.13.46 → ingestr-0.13.48}/.githooks/pre-commit-hook.sh +0 -0
  16. {ingestr-0.13.46 → ingestr-0.13.48}/.github/workflows/deploy-docs.yml +0 -0
  17. {ingestr-0.13.46 → ingestr-0.13.48}/.github/workflows/release.yml +0 -0
  18. {ingestr-0.13.46 → ingestr-0.13.48}/.github/workflows/secrets-scan.yml +0 -0
  19. {ingestr-0.13.46 → ingestr-0.13.48}/.github/workflows/tests.yml +0 -0
  20. {ingestr-0.13.46 → ingestr-0.13.48}/.gitignore +0 -0
  21. {ingestr-0.13.46 → ingestr-0.13.48}/.gitleaksignore +0 -0
  22. {ingestr-0.13.46 → ingestr-0.13.48}/.python-version +0 -0
  23. {ingestr-0.13.46 → ingestr-0.13.48}/.vale.ini +0 -0
  24. {ingestr-0.13.46 → ingestr-0.13.48}/Dockerfile +0 -0
  25. {ingestr-0.13.46 → ingestr-0.13.48}/LICENSE.md +0 -0
  26. {ingestr-0.13.46 → ingestr-0.13.48}/Makefile +0 -0
  27. {ingestr-0.13.46 → ingestr-0.13.48}/README.md +0 -0
  28. {ingestr-0.13.46 → ingestr-0.13.48}/docs/.vitepress/theme/custom.css +0 -0
  29. {ingestr-0.13.46 → ingestr-0.13.48}/docs/.vitepress/theme/index.js +0 -0
  30. {ingestr-0.13.46 → ingestr-0.13.48}/docs/commands/example-uris.md +0 -0
  31. {ingestr-0.13.46 → ingestr-0.13.48}/docs/commands/ingest.md +0 -0
  32. {ingestr-0.13.46 → ingestr-0.13.48}/docs/getting-started/core-concepts.md +0 -0
  33. {ingestr-0.13.46 → ingestr-0.13.48}/docs/getting-started/incremental-loading.md +0 -0
  34. {ingestr-0.13.46 → ingestr-0.13.48}/docs/getting-started/quickstart.md +0 -0
  35. {ingestr-0.13.46 → ingestr-0.13.48}/docs/getting-started/telemetry.md +0 -0
  36. {ingestr-0.13.46 → ingestr-0.13.48}/docs/index.md +0 -0
  37. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/applovin_max.png +0 -0
  38. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/athena.png +0 -0
  39. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/clickhouse_img.png +0 -0
  40. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/freshdesk_ingestion.png +0 -0
  41. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/github.png +0 -0
  42. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/google_analytics_realtime_report.png +0 -0
  43. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/googleanalytics.png +0 -0
  44. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/ingestion_elasticsearch_img.png +0 -0
  45. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/kinesis.bigquery.png +0 -0
  46. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/linkedin_ads.png +0 -0
  47. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/personio.png +0 -0
  48. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/personio_duckdb.png +0 -0
  49. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/phantombuster.png +0 -0
  50. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/pipedrive.png +0 -0
  51. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/spanner_ingestion.png +0 -0
  52. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/stripe_postgres.png +0 -0
  53. {ingestr-0.13.46 → ingestr-0.13.48}/docs/media/tiktok.png +0 -0
  54. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/adjust.md +0 -0
  55. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/airtable.md +0 -0
  56. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/applovin.md +0 -0
  57. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/applovin_max.md +0 -0
  58. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/appsflyer.md +0 -0
  59. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/appstore.md +0 -0
  60. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/asana.md +0 -0
  61. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/athena.md +0 -0
  62. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/attio.md +0 -0
  63. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/bigquery.md +0 -0
  64. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/chess.md +0 -0
  65. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/clickhouse.md +0 -0
  66. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/csv.md +0 -0
  67. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/custom_queries.md +0 -0
  68. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/databricks.md +0 -0
  69. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/db2.md +0 -0
  70. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/duckdb.md +0 -0
  71. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/dynamodb.md +0 -0
  72. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/elasticsearch.md +0 -0
  73. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/facebook-ads.md +0 -0
  74. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/freshdesk.md +0 -0
  75. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/gcs.md +0 -0
  76. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/github.md +0 -0
  77. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/google-ads.md +0 -0
  78. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/google_analytics.md +0 -0
  79. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/gorgias.md +0 -0
  80. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/gsheets.md +0 -0
  81. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/hubspot.md +0 -0
  82. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/kafka.md +0 -0
  83. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/kinesis.md +0 -0
  84. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/klaviyo.md +0 -0
  85. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/linkedin_ads.md +0 -0
  86. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/mongodb.md +0 -0
  87. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/mssql.md +0 -0
  88. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/mysql.md +0 -0
  89. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/notion.md +0 -0
  90. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/oracle.md +0 -0
  91. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/personio.md +0 -0
  92. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/phantombuster.md +0 -0
  93. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/pipedrive.md +0 -0
  94. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/postgres.md +0 -0
  95. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/redshift.md +0 -0
  96. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/salesforce.md +0 -0
  97. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/sap-hana.md +0 -0
  98. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/shopify.md +0 -0
  99. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/slack.md +0 -0
  100. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/snowflake.md +0 -0
  101. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/spanner.md +0 -0
  102. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/sqlite.md +0 -0
  103. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/stripe.md +0 -0
  104. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/tiktok-ads.md +0 -0
  105. {ingestr-0.13.46 → ingestr-0.13.48}/docs/supported-sources/zendesk.md +0 -0
  106. {ingestr-0.13.46 → ingestr-0.13.48}/docs/tutorials/load-kinesis-bigquery.md +0 -0
  107. {ingestr-0.13.46 → ingestr-0.13.48}/docs/tutorials/load-personio-duckdb.md +0 -0
  108. {ingestr-0.13.46 → ingestr-0.13.48}/docs/tutorials/load-stripe-postgres.md +0 -0
  109. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/conftest.py +0 -0
  110. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/main.py +0 -0
  111. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/.gitignore +0 -0
  112. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/adjust/__init__.py +0 -0
  113. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/adjust/adjust_helpers.py +0 -0
  114. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/airtable/__init__.py +0 -0
  115. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/applovin/__init__.py +0 -0
  116. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/applovin_max/__init__.py +0 -0
  117. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/appsflyer/__init__.py +0 -0
  118. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/appsflyer/client.py +0 -0
  119. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/appstore/__init__.py +0 -0
  120. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/appstore/client.py +0 -0
  121. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/appstore/errors.py +0 -0
  122. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/appstore/models.py +0 -0
  123. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/appstore/resources.py +0 -0
  124. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/arrow/__init__.py +0 -0
  125. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/asana_source/__init__.py +0 -0
  126. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/asana_source/helpers.py +0 -0
  127. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/asana_source/settings.py +0 -0
  128. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/attio/__init__.py +0 -0
  129. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/attio/helpers.py +0 -0
  130. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/blob.py +0 -0
  131. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/chess/__init__.py +0 -0
  132. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/chess/helpers.py +0 -0
  133. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/chess/settings.py +0 -0
  134. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/collector/spinner.py +0 -0
  135. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/destinations.py +0 -0
  136. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/dynamodb/__init__.py +0 -0
  137. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/elasticsearch/__init__.py +0 -0
  138. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/errors.py +0 -0
  139. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/facebook_ads/__init__.py +0 -0
  140. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/facebook_ads/exceptions.py +0 -0
  141. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/facebook_ads/helpers.py +0 -0
  142. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/facebook_ads/settings.py +0 -0
  143. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/filesystem/__init__.py +0 -0
  144. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/filesystem/helpers.py +0 -0
  145. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/filesystem/readers.py +0 -0
  146. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/filters.py +0 -0
  147. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/frankfurter/__init__.py +0 -0
  148. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/frankfurter/helpers.py +0 -0
  149. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/freshdesk/__init__.py +0 -0
  150. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/freshdesk/freshdesk_client.py +0 -0
  151. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/freshdesk/settings.py +0 -0
  152. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/github/__init__.py +0 -0
  153. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/github/helpers.py +0 -0
  154. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/github/queries.py +0 -0
  155. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/github/settings.py +0 -0
  156. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/google_ads/__init__.py +0 -0
  157. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/google_ads/field.py +0 -0
  158. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/google_ads/metrics.py +0 -0
  159. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/google_ads/predicates.py +0 -0
  160. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/google_ads/reports.py +0 -0
  161. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/google_analytics/__init__.py +0 -0
  162. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/google_analytics/helpers.py +0 -0
  163. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/google_sheets/README.md +0 -0
  164. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/google_sheets/__init__.py +0 -0
  165. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
  166. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
  167. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
  168. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/gorgias/__init__.py +0 -0
  169. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/gorgias/helpers.py +0 -0
  170. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/http_client.py +0 -0
  171. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/hubspot/__init__.py +0 -0
  172. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/hubspot/helpers.py +0 -0
  173. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/hubspot/settings.py +0 -0
  174. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/kafka/__init__.py +0 -0
  175. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/kafka/helpers.py +0 -0
  176. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/kinesis/__init__.py +0 -0
  177. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/kinesis/helpers.py +0 -0
  178. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/klaviyo/__init__.py +0 -0
  179. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/klaviyo/client.py +0 -0
  180. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/klaviyo/helpers.py +0 -0
  181. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/linkedin_ads/__init__.py +0 -0
  182. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/linkedin_ads/dimension_time_enum.py +0 -0
  183. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/linkedin_ads/helpers.py +0 -0
  184. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/loader.py +0 -0
  185. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/mongodb/__init__.py +0 -0
  186. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/mongodb/helpers.py +0 -0
  187. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/notion/__init__.py +0 -0
  188. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/notion/helpers/__init__.py +0 -0
  189. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/notion/helpers/client.py +0 -0
  190. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/notion/helpers/database.py +0 -0
  191. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/notion/settings.py +0 -0
  192. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/partition.py +0 -0
  193. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/personio/__init__.py +0 -0
  194. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/personio/helpers.py +0 -0
  195. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/phantombuster/__init__.py +0 -0
  196. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/phantombuster/client.py +0 -0
  197. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/pipedrive/__init__.py +0 -0
  198. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/pipedrive/helpers/__init__.py +0 -0
  199. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/pipedrive/helpers/custom_fields_munger.py +0 -0
  200. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/pipedrive/helpers/pages.py +0 -0
  201. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/pipedrive/settings.py +0 -0
  202. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/pipedrive/typing.py +0 -0
  203. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/resource.py +0 -0
  204. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/salesforce/__init__.py +0 -0
  205. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/salesforce/helpers.py +0 -0
  206. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/shopify/__init__.py +0 -0
  207. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/shopify/exceptions.py +0 -0
  208. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/shopify/helpers.py +0 -0
  209. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/shopify/settings.py +0 -0
  210. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/slack/__init__.py +0 -0
  211. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/slack/helpers.py +0 -0
  212. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/slack/settings.py +0 -0
  213. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/sql_database/__init__.py +0 -0
  214. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/sql_database/callbacks.py +0 -0
  215. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/stripe_analytics/__init__.py +0 -0
  216. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/stripe_analytics/helpers.py +0 -0
  217. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/stripe_analytics/settings.py +0 -0
  218. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/table_definition.py +0 -0
  219. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/telemetry/event.py +0 -0
  220. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/testdata/fakebqcredentials.json +0 -0
  221. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/tiktok_ads/__init__.py +0 -0
  222. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/tiktok_ads/tiktok_helpers.py +0 -0
  223. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/time.py +0 -0
  224. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/version.py +0 -0
  225. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/zendesk/__init__.py +0 -0
  226. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/zendesk/helpers/__init__.py +0 -0
  227. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
  228. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/zendesk/helpers/credentials.py +0 -0
  229. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
  230. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/src/zendesk/settings.py +0 -0
  231. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/testdata/.gitignore +0 -0
  232. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/testdata/create_replace.csv +0 -0
  233. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/testdata/delete_insert_expected.csv +0 -0
  234. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/testdata/delete_insert_part1.csv +0 -0
  235. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/testdata/delete_insert_part2.csv +0 -0
  236. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/testdata/merge_expected.csv +0 -0
  237. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/testdata/merge_part1.csv +0 -0
  238. {ingestr-0.13.46 → ingestr-0.13.48}/ingestr/testdata/merge_part2.csv +0 -0
  239. {ingestr-0.13.46 → ingestr-0.13.48}/package-lock.json +0 -0
  240. {ingestr-0.13.46 → ingestr-0.13.48}/package.json +0 -0
  241. {ingestr-0.13.46 → ingestr-0.13.48}/pyproject.toml +0 -0
  242. {ingestr-0.13.46 → ingestr-0.13.48}/requirements-dev.txt +0 -0
  243. {ingestr-0.13.46 → ingestr-0.13.48}/requirements.in +0 -0
  244. {ingestr-0.13.46 → ingestr-0.13.48}/requirements.txt +0 -0
  245. {ingestr-0.13.46 → ingestr-0.13.48}/requirements_arm64.txt +0 -0
  246. {ingestr-0.13.46 → ingestr-0.13.48}/resources/demo.gif +0 -0
  247. {ingestr-0.13.46 → ingestr-0.13.48}/resources/demo.tape +0 -0
  248. {ingestr-0.13.46 → ingestr-0.13.48}/resources/ingestr.svg +0 -0
  249. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/AMPM.yml +0 -0
  250. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Acronyms.yml +0 -0
  251. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Colons.yml +0 -0
  252. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Contractions.yml +0 -0
  253. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/DateFormat.yml +0 -0
  254. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Ellipses.yml +0 -0
  255. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/EmDash.yml +0 -0
  256. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Exclamation.yml +0 -0
  257. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/FirstPerson.yml +0 -0
  258. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Gender.yml +0 -0
  259. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/GenderBias.yml +0 -0
  260. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/HeadingPunctuation.yml +0 -0
  261. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Headings.yml +0 -0
  262. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Latin.yml +0 -0
  263. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/LyHyphens.yml +0 -0
  264. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/OptionalPlurals.yml +0 -0
  265. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Ordinal.yml +0 -0
  266. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/OxfordComma.yml +0 -0
  267. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Parens.yml +0 -0
  268. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Passive.yml +0 -0
  269. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Periods.yml +0 -0
  270. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Quotes.yml +0 -0
  271. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Ranges.yml +0 -0
  272. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Semicolons.yml +0 -0
  273. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Slang.yml +0 -0
  274. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Spacing.yml +0 -0
  275. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Spelling.yml +0 -0
  276. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Units.yml +0 -0
  277. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/We.yml +0 -0
  278. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/Will.yml +0 -0
  279. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/WordList.yml +0 -0
  280. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/meta.json +0 -0
  281. {ingestr-0.13.46 → ingestr-0.13.48}/styles/Google/vocab.txt +0 -0
  282. {ingestr-0.13.46 → ingestr-0.13.48}/styles/bruin/Ingestr.yml +0 -0
  283. {ingestr-0.13.46 → ingestr-0.13.48}/styles/config/vocabularies/bruin/accept.txt +0 -0
  284. {ingestr-0.13.46 → ingestr-0.13.48}/test.env.template +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ingestr
3
- Version: 0.13.46
3
+ Version: 0.13.48
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
@@ -140,6 +140,7 @@ export default defineConfig({
140
140
  { text: "Shopify", link: "/supported-sources/shopify.md" },
141
141
  { text: "Slack", link: "/supported-sources/slack.md" },
142
142
  { text: "Spanner", link: "/supported-sources/spanner.md" },
143
+ { text: "Solidgate", link: "/supported-sources/solidgate.md" },
143
144
  { text: "Stripe", link: "/supported-sources/stripe.md" },
144
145
  { text: "TikTok Ads", link: "/supported-sources/tiktok-ads.md" },
145
146
  { text: "Zendesk", link: "/supported-sources/zendesk.md" },
@@ -0,0 +1,48 @@
1
+ # Frankfurter
2
+
3
+ [Frankfurter API](https://www.frankfurter.dev/) is an online platform which fetches current and historical exchnge rate data.
4
+
5
+ ingestr supports Frankfurter as a source primarily to demonstrate ingestr's features since the API doesn't require any authentication.
6
+
7
+ ## URI format
8
+
9
+ The URI format for Frankfurter is as follows:
10
+
11
+ ```plaintext
12
+ frankfurter://?base=<currency-code-here>
13
+ ```
14
+
15
+ URI parameters:
16
+ - `base`: defines the base currency code (e.g. EUR, USD, IDR) used to calculate the exchange rates.
17
+
18
+
19
+ ## Set-Up Frankfurter Integration
20
+
21
+ Let's say you want to fetch the exchange rates for a certain period with the base currency as Indian Rupees. Here's a sample command that will copy this data into your DuckDB database:
22
+
23
+ ```bash
24
+ ingestr ingest \
25
+ --source-uri 'frankfurter://?base=INR' \
26
+ --interval-start '2025-03-20' \
27
+ --interval-end '2025-03-28' \
28
+ --source-table 'exchange_rates' \
29
+ --dest-uri 'duckdb///frankfurter.duckdb' \
30
+ --dest-table 'my_schema.exchange_rates'
31
+ ```
32
+
33
+ The result of this command will be a list of currency exchange rates from 20.03.2025-28.03.2025 with INR as the base currency in your DuckDB database.
34
+
35
+ ## Tables
36
+
37
+ - `latest`: Fetches the latest exchange rates.
38
+ - `exchange_rates`: Fetches historical exchange rates for a specified date range.
39
+ - `currencies`: Fetches a list of the available currencies and their ISO 4217 currency code (e.g. `USD`, `EUR`, `GBP`).
40
+
41
+ Use these as `--source-table` parameter in the `ingestr ingest` command.
42
+
43
+
44
+ **Notes**:
45
+ - The arguments `--interval-start` and `--interval-end` are only relevant for the table exchange_rates.
46
+ - If a start date but no end date is specified, then the end date will default to today's date and ingestr will retrieve data up until the latest published data.
47
+ - Note that the [Frankfurter API](https://www.frankfurter.dev/) only publishes updates Monday-Friday. If the given date is on the weekend, the date will default to the previous Friday.
48
+
@@ -0,0 +1,136 @@
1
+ # Amazon S3
2
+
3
+ Amazon Simple Storage Service (S3) is a scalable cloud storage service offered by Amazon Web Services (AWS). It allows users to store and retrieve extensive amounts of data from anywhere on the web.
4
+
5
+ `ingestr` supports Amazon S3 as both a data source and destination.
6
+
7
+ ## URI Format
8
+
9
+ The URI for connecting to Amazon S3 is structured as follows:
10
+
11
+ ```plaintext
12
+ s3://?access_key_id=<your_access_key_id>&secret_access_key=<your_secret_access_key>
13
+ ```
14
+
15
+ **URI Parameters:**
16
+
17
+ * `access_key_id`: Your AWS access key ID.
18
+ * `secret_access_key`: Your AWS secret access key.
19
+ * `endpoint_url`: URL of an S3-Compatiable API Server (optional, destination only)
20
+ * `layout`: Layout template (optional, destination only)
21
+
22
+ These credentials are required to authenticate and authorize access to your S3 buckets.
23
+
24
+ The `--source-table` parameter specifies the S3 bucket and file pattern using the following format:
25
+
26
+ ```
27
+ <bucket-name>/<file-glob-pattern>
28
+ ```
29
+
30
+ ## Setting up an S3 Integration
31
+
32
+ To integrate `ingestr` with Amazon S3, you need an `access_key_id` and a `secret_access_key`. For guidance on obtaining these credentials, refer to the dltHub documentation on [AWS credentials](https://dlthub.com/docs/dlt-ecosystem/verified-sources/filesystem/basic#get-credentials).
33
+
34
+ Once you have your credentials, you can configure the S3 URI. The `bucket_name` and `path_to_files` (file glob pattern) are specified in the `--source-table` argument.
35
+
36
+ ### Example: Loading data from S3
37
+
38
+ Let's assume the following details:
39
+ * `access_key_id`: `AKC3YOW7E`
40
+ * `secret_access_key`: `XCtkpL5B`
41
+ * S3 bucket name: `my_bucket`
42
+ * Path to files within the bucket: `students/students_details.csv`
43
+
44
+ The following command demonstrates how to copy data from the specified S3 location to a DuckDB database:
45
+
46
+ ```sh
47
+ ingestr ingest \
48
+ --source-uri 's3://?access_key_id=AKC3YOW7E&secret_access_key=XCtkpL5B' \
49
+ --source-table 'my_bucket/students/students_details.csv' \
50
+ --dest-uri duckdb:///s3_data.duckdb \
51
+ --dest-table 'processed_students.student_details'
52
+ ```
53
+
54
+ This command will create a table named `student_details` within the `processed_students` schema (or equivalent grouping) in the DuckDB database file located at `s3_data.duckdb`.
55
+
56
+ ### Example: Uploading data to S3
57
+ For this, example we'll assume that:
58
+ * `records.db` is a duckdb database.
59
+ * has a table called `public.users`.
60
+ * the S3 credentials are the same as the example above.
61
+
62
+ The following command demonstrates how to copy data from a local duckdb database to S3:
63
+ ```sh
64
+ ingestr ingest \
65
+ --source-uri 'duckdb:///records.db' \
66
+ --source-table 'public.users' \
67
+ --dest-uri 's3://?access_key_id=AKC3YOW7E&secret_access_key=XCtkpL5B' \
68
+ --dest-table 'my_bucket/records'
69
+ ```
70
+
71
+ This will result in a file structure like the following:
72
+ ```
73
+ my_bucket/
74
+ └── records
75
+ ├── _dlt_loads
76
+ ├── _dlt_pipeline_state
77
+ ├── _dlt_version
78
+ └── users
79
+ └── <load_id>.<file_id>.parquet
80
+ ```
81
+
82
+ The value of `load_id` and `file_id` is determined at runtime. The default layout creates a folder with the same table name as the source and places the data inside a parquet file. This layout is configurable using the `layout` parameter.
83
+
84
+ For example, if you would like to create a parquet file with the same name as the source table (as opposed to a folder) you can set `layout` to `{table_name}.{ext}` in the commandline above:
85
+
86
+ ```sh
87
+ ingestr ingest \
88
+ --source-uri 'duckdb:///records.db' \
89
+ --source-table 'public.users' \
90
+ --dest-uri 's3://?layout={table_name}.{ext}&access_key_id=AKC3YOW7E&secret_access_key=XCtkpL5B' \
91
+ --dest-table 'my_bucket/records'
92
+ ```
93
+
94
+ Result:
95
+ ```
96
+ my_bucket/
97
+ └── records
98
+ ├── _dlt_loads
99
+ ├── _dlt_pipeline_state
100
+ ├── _dlt_version
101
+ └── users.parquet
102
+ ```
103
+
104
+ List of available Layout variables is available [here](https://dlthub.com/docs/dlt-ecosystem/destinations/filesystem#available-layout-placeholders)
105
+
106
+ ### Working with S3-Compatiable object stores
107
+ `ingestr` support S3 compatiable storage services like [Minio](https://min.io/), Digital Ocean [spaces](https://www.digitalocean.com/products/spaces) and Cloudflare [R2](https://developers.cloudflare.com/r2/). You can set the `endpoint_url` in your destination URI to write data to these object stores.
108
+
109
+ For example, if you're running minio on `localhost:9000`, you can write the same data as the [example above](#example-uploading-data-to-s3) by running:
110
+ ```sh
111
+ ingestr ingest \
112
+ --source-uri 'duckdb:///records.db' \
113
+ --source-table 'public.users' \
114
+ --dest-uri 's3://?endpoint_url=http://localhost:9000&access_key_id=AKC3YOW7E&secret_access_key=XCtkpL5B' \
115
+ --dest-table 'my_bucket/records'
116
+ ```
117
+
118
+ ::: info NOTE
119
+ S3-Compatiable object stores are currently only supported as destinations.
120
+ :::
121
+
122
+ ### File Glob Pattern Examples:
123
+
124
+ ::: warning
125
+ Glob patterns only apply when loading data from S3 as source.
126
+ :::
127
+
128
+ The `<file-glob-pattern>` in the `--source-table` argument allows for flexible file selection. Here are some common patterns and their descriptions:
129
+
130
+ | Pattern | Description |
131
+ | :------------------------------------------ | :--------------------------------------------------------------------------------------------------------- |
132
+ | `bucket/**/*.csv` | Retrieves all CSV files recursively from `s3://bucket`. |
133
+ | `bucket/*.csv` | Retrieves all CSV files located at the root level of `s3://bucket`. |
134
+ | `bucket/myFolder/**/*.jsonl` | Retrieves all JSONL files recursively from the `myFolder` directory and its subdirectories in `s3://bucket`. |
135
+ | `bucket/myFolder/mySubFolder/users.parquet` | Retrieves the specific `users.parquet` file from the `myFolder/mySubFolder/` path in `s3://bucket`. |
136
+ | `bucket/employees.jsonl` | Retrieves the `employees.jsonl` file located at the root level of the `s3://bucket`. |
@@ -0,0 +1,46 @@
1
+ # Solidgate
2
+
3
+ [Solidgate](https://solidgate.com//) is a one-stop payment processing platform that ensures seamless online purchases and streamlined payment infrastructure.
4
+
5
+ ingestr supports Solidgate as a source.
6
+
7
+ ## URI format
8
+
9
+ The URI format for Solidgate is as follows:
10
+
11
+ ```plaintext
12
+ solidgate://?public_key=<your-public-key>&secret_key=<your-secret-key>
13
+ ```
14
+
15
+ URI parameters:
16
+
17
+ - `public_key`: The public API key used to identify the account.
18
+
19
+ - `secret_key`: The secret API key used to authenticate requests to the Solidgate API.
20
+
21
+
22
+ ## Setting up a Solidgate Integration
23
+
24
+ Solidgate requires a few steps to set up an integration. Please follow the [guide](https://docs.solidgate.com/payments/integrate/access-to-api/#retrieve-your-credentials).
25
+
26
+ Once you complete the guide, you should have `public_key` and `secret_key`, here’s a sample command that ingests data from Solidgate into a DuckDB database:
27
+
28
+ ```sh
29
+ ingestr ingestr ingest \
30
+ --source-uri "solidgate://?public_key=api_pk_test&secret_key=api_sk_test" \
31
+ --source-table "apm-orders" \
32
+ --dest-uri "duckdb:///solidgate.db" \
33
+ --dest-table "dest.apmorders"
34
+ ```
35
+
36
+ The result of this command will be a table in the `Solidgate.duckdb` database with JSON columns.
37
+
38
+ ## Tables
39
+
40
+ Solidgate source allows ingesting the following sources into separate tables:
41
+ - `subscriptions`: Provides a comprehensive view of customer subscriptions, including subscription IDs, statuses, and key timestamps such as creation, update, and expiration dates.
42
+ - `apm-orders`: Provides essential information for anti-fraud purposes, including order IDs, transaction statuses, amounts, currencies, and payment methods, along with crucial customer details such as email addresses.
43
+ - `card-orders`: Provides detailed information on orders processed via card payments, including transaction data, payment status, and customer details.
44
+
45
+ Use these as `--source-table` parameter in the `ingestr ingest` command.
46
+
@@ -0,0 +1 @@
1
+ version = "v0.13.48"
@@ -54,6 +54,7 @@ from ingestr.src.sources import (
54
54
  SalesforceSource,
55
55
  ShopifySource,
56
56
  SlackSource,
57
+ SolidgateSource,
57
58
  SqlSource,
58
59
  StripeAnalyticsSource,
59
60
  TikTokSource,
@@ -159,6 +160,7 @@ class SourceDestinationFactory:
159
160
  "phantombuster": PhantombusterSource,
160
161
  "elasticsearch": ElasticsearchSource,
161
162
  "attio": AttioSource,
163
+ "solidgate": SolidgateSource,
162
164
  }
163
165
  destinations: Dict[str, Type[DestinationProtocol]] = {
164
166
  "bigquery": BigQueryDestination,
@@ -0,0 +1,97 @@
1
+ from typing import Iterable, Iterator
2
+
3
+ import dlt
4
+ import pendulum
5
+ from dlt.sources import DltResource
6
+
7
+ from .helpers import SolidgateClient
8
+
9
+
10
+ @dlt.source(max_table_nesting=0)
11
+ def solidgate_source(
12
+ start_date: pendulum.DateTime,
13
+ end_date: pendulum.DateTime | None,
14
+ public_key: str,
15
+ secret_key: str,
16
+ ) -> Iterable[DltResource]:
17
+ solidgate_client = SolidgateClient(public_key, secret_key)
18
+
19
+ @dlt.resource(
20
+ name="subscriptions",
21
+ write_disposition="merge",
22
+ primary_key="id",
23
+ columns={
24
+ "created_at": {"data_type": "timestamp", "partition": True},
25
+ },
26
+ )
27
+ def fetch_all_subscriptions(
28
+ dateTime=dlt.sources.incremental(
29
+ "updated_at",
30
+ initial_value=start_date,
31
+ end_value=end_date,
32
+ range_start="closed",
33
+ range_end="closed",
34
+ ),
35
+ ) -> Iterator[dict]:
36
+ path = "subscriptions"
37
+ if dateTime.end_value is None:
38
+ end_dt = pendulum.now(tz="UTC")
39
+ else:
40
+ end_dt = dateTime.end_value
41
+
42
+ start_dt = dateTime.last_value
43
+ yield solidgate_client.fetch_data(path, date_from=start_dt, date_to=end_dt)
44
+
45
+ @dlt.resource(
46
+ name="apm-orders",
47
+ write_disposition="merge",
48
+ primary_key="order_id",
49
+ columns={
50
+ "created_at": {"data_type": "timestamp", "partition": True},
51
+ },
52
+ )
53
+ def fetch_apm_orders(
54
+ dateTime=dlt.sources.incremental(
55
+ "updated_at",
56
+ initial_value=start_date,
57
+ end_value=end_date,
58
+ range_start="closed",
59
+ range_end="closed",
60
+ ),
61
+ ) -> Iterator[dict]:
62
+ path = "apm-orders"
63
+ if dateTime.end_value is None:
64
+ end_dt = pendulum.now(tz="UTC")
65
+ else:
66
+ end_dt = dateTime.end_value
67
+
68
+ start_dt = dateTime.last_value
69
+ yield solidgate_client.fetch_data(path, date_from=start_dt, date_to=end_dt)
70
+
71
+ @dlt.resource(
72
+ name="card-orders",
73
+ write_disposition="merge",
74
+ primary_key="order_id",
75
+ columns={
76
+ "created_at": {"data_type": "timestamp", "partition": True},
77
+ },
78
+ )
79
+ def fetch_card_orders(
80
+ dateTime=dlt.sources.incremental(
81
+ "updated_at",
82
+ initial_value=start_date,
83
+ end_value=end_date,
84
+ range_start="closed",
85
+ range_end="closed",
86
+ ),
87
+ ) -> Iterator[dict]:
88
+ path = "card-orders"
89
+ if dateTime.end_value is None:
90
+ end_dt = pendulum.now(tz="UTC")
91
+ else:
92
+ end_dt = dateTime.end_value
93
+
94
+ start_dt = dateTime.last_value
95
+ yield solidgate_client.fetch_data(path, date_from=start_dt, date_to=end_dt)
96
+
97
+ return fetch_all_subscriptions, fetch_apm_orders, fetch_card_orders
@@ -0,0 +1,78 @@
1
+ import base64
2
+ import hashlib
3
+ import hmac
4
+ import json
5
+
6
+ import pendulum
7
+
8
+ from ingestr.src.http_client import create_client
9
+
10
+
11
+ class SolidgateClient:
12
+ def __init__(self, public_key, secret_key):
13
+ self.base_url = "https://reports.solidgate.com/api/v1"
14
+ self.public_key = public_key
15
+ self.secret_key = secret_key
16
+ self.client = create_client()
17
+
18
+ def fetch_data(
19
+ self,
20
+ path: str,
21
+ date_from: pendulum.DateTime,
22
+ date_to: pendulum.DateTime,
23
+ ):
24
+ request_payload = {
25
+ "date_from": date_from.format("YYYY-MM-DD HH:mm:ss"),
26
+ "date_to": date_to.format("YYYY-MM-DD HH:mm:ss"),
27
+ }
28
+
29
+ json_string = json.dumps(request_payload)
30
+ signature = self.generateSignature(json_string)
31
+ headers = {
32
+ "merchant": self.public_key,
33
+ "Signature": signature,
34
+ "Content-Type": "application/json",
35
+ }
36
+
37
+ next_page_iterator = None
38
+ url = f"{self.base_url}/{path}"
39
+
40
+ while True:
41
+ payload = request_payload.copy()
42
+ if next_page_iterator:
43
+ payload["page_iterator"] = next_page_iterator
44
+
45
+ response = self.client.post(url, headers=headers, json=payload)
46
+ response.raise_for_status()
47
+ response_json = response.json()
48
+
49
+ if path == "subscriptions":
50
+ data = response_json["subscriptions"]
51
+ for _, value in data.items():
52
+ if "updated_at" in value:
53
+ value["updated_at"] = pendulum.parse(
54
+ value["updated_at"]
55
+ )
56
+ yield value
57
+
58
+ else:
59
+ data = response_json["orders"]
60
+ for value in data:
61
+ if "updated_at" in value:
62
+ value["updated_at"] = pendulum.parse(
63
+ value["updated_at"]
64
+ )
65
+ yield value
66
+
67
+ next_page_iterator = response_json.get("metadata", {}).get(
68
+ "next_page_iterator"
69
+ )
70
+ if not next_page_iterator or next_page_iterator == "None":
71
+ break
72
+
73
+ def generateSignature(self, json_string):
74
+ data = self.public_key + json_string + self.public_key
75
+ hmac_hash = hmac.new(
76
+ self.secret_key.encode("utf-8"), data.encode("utf-8"), hashlib.sha512
77
+ ).digest()
78
+ return base64.b64encode(hmac_hash.hex().encode("utf-8")).decode("utf-8")
@@ -698,7 +698,10 @@ class StripeAnalyticsSource:
698
698
  raise ValueError("api_key in the URI is required to connect to Stripe")
699
699
 
700
700
  endpoint = None
701
- table = str.capitalize(table)
701
+ if table == "balancetransaction":
702
+ table = "BalanceTransaction"
703
+ else:
704
+ table = table.capitalize()
702
705
 
703
706
  if table in [
704
707
  "Subscription",
@@ -2428,3 +2431,45 @@ class AttioSource:
2428
2431
  )
2429
2432
  except ResourcesNotFoundError:
2430
2433
  raise UnsupportedResourceError(table_name, "Attio")
2434
+
2435
+
2436
+ class SolidgateSource:
2437
+ def handles_incrementality(self) -> bool:
2438
+ return True
2439
+
2440
+ def dlt_source(self, uri: str, table: str, **kwargs):
2441
+ parsed_uri = urlparse(uri)
2442
+ query_params = parse_qs(parsed_uri.query)
2443
+ public_key = query_params.get("public_key")
2444
+ secret_key = query_params.get("secret_key")
2445
+
2446
+ if public_key is None:
2447
+ raise MissingValueError("public_key", "Solidgate")
2448
+
2449
+ if secret_key is None:
2450
+ raise MissingValueError("secret_key", "Solidgate")
2451
+
2452
+ table_name = table.replace(" ", "")
2453
+
2454
+ start_date = kwargs.get("interval_start")
2455
+ if start_date is None:
2456
+ start_date = pendulum.yesterday().in_tz("UTC")
2457
+ else:
2458
+ start_date = ensure_pendulum_datetime(start_date).in_tz("UTC")
2459
+
2460
+ end_date = kwargs.get("interval_end")
2461
+
2462
+ if end_date is not None:
2463
+ end_date = ensure_pendulum_datetime(end_date).in_tz("UTC")
2464
+
2465
+ from ingestr.src.solidgate import solidgate_source
2466
+
2467
+ try:
2468
+ return solidgate_source(
2469
+ public_key=public_key[0],
2470
+ secret_key=secret_key[0],
2471
+ start_date=start_date,
2472
+ end_date=end_date,
2473
+ ).with_resources(table_name)
2474
+ except ResourcesNotFoundError:
2475
+ raise UnsupportedResourceError(table_name, "Solidgate")
@@ -1,173 +0,0 @@
1
- # **Frankfurter Source Documentation**
2
-
3
- The `frankfurter` source in the `ingestr` pipeline is designed to fetch exchange rate data from the [Frankfurter API](https://www.frankfurter.dev/). This source supports fetching the latest exchange rates, historical exchange rates, and currency metadata. The data can be ingested into a specified destination database, such as DuckDB.
4
-
5
- ---
6
-
7
- ## **Command Overview**
8
-
9
- The `ingestr` command to use the `frankfurter` source is as follows:
10
-
11
- ```bash
12
- ingestr ingest \
13
- --source-uri 'frankfurter://?base=IDR' \
14
- --interval-start '2025-03-27' \ # Optional. See 'exchange_rates'.
15
- --interval-end '2025-03-28' \ # Optional.
16
- --source-table '<table_name>' \ # E.g 'currencies', 'latest', 'exchange_rates'. See below.
17
- --dest-uri '<your-destination-uri>' \
18
- --dest-table '<your-schema>.<your-table_name>'
19
- ```
20
-
21
- ---
22
-
23
- ## **Command Parameters**
24
-
25
- ### **`--source-uri`**
26
- - **Description**: Specifies the source URI for the Frankfurter API.
27
- - **Value**: `'frankfurter://'`
28
- - **Purpose**: Indicates that the data will be fetched from the Frankfurter API.
29
- - An optional base currency can be added `?base={base_currency}`.
30
- - If no base currency is included, base currency defaults to USD.
31
-
32
- ---
33
-
34
- ### **`--interval-start` (Optional)**
35
- - **Description**: The start date for fetching historical exchange rates.
36
- - **Value**: A date in the format `YYYY-MM-DD` (e.g., `'2025-03-27'`).
37
- - **Purpose**: Defines the starting point for fetching historical data.
38
- - For `latest` and `currencies` this parameter is ignored.
39
- - For `exchange_rates`, it defaults to the current date if not provided.
40
-
41
- ---
42
-
43
- ### **`--interval-end` (Optional)**
44
- - **Description**: The end date for fetching historical exchange rates.
45
- - **Value**: A date in the format `YYYY-MM-DD` (e.g., `'2025-03-28'`).
46
- - **Purpose**: Defines the end point for fetching historical data.
47
- - If `--interval-start` is provided without `--interval-end`, `--interval-end` defaults to the current date and retrieves up until the latest published data.
48
- - If `--interval-end` is provided without `--interval-start`, it will be ignored and the call will retrieve the last published data.
49
- - For `latest` and `currencies` this parameter is ignored.
50
-
51
- ---
52
-
53
- ### **`--source-table`**
54
- - **Description**: Specifies the table to fetch data from.
55
- - **Value**: One of the following:
56
- - **`currencies`**: Fetches a list of the available currencies and their ISO 4217 currency code (e.g. `USD`, `EUR`, `GBP`).
57
- - **`latest`**: Fetches the latest exchange rates.
58
- - **`exchange_rates`**: Fetches historical exchange rates for a specified date range.
59
- - **Purpose**: Determines the type of data to fetch from the Frankfurter API.
60
-
61
- ---
62
-
63
- ### **`--dest-uri`**
64
- - **Description**: Specifies the destination database URI.
65
- - **Value**: The path to the database file (e.g., `'duckdb.db'`).
66
- - **Purpose**: Defines where the fetched data will be stored.
67
-
68
- ---
69
-
70
- ### **`--dest-table`**
71
- - **Description**: Specifies the destination table name.
72
- - **Value**: A string in the format `{schema}.{table_name}` (e.g., `'schema.my_table'`).
73
- - **Purpose**: Defines the schema and table name where the data will be written.
74
- - **Notes**:
75
- - If the destination table does not yet exist in your database, ingestr will automatically create the table with name that is provided in this argument. The table will be structured according to the source table (see [Core Concepts](https://bruin-data.github.io/ingestr/getting-started/core-concepts.html)).
76
-
77
- ---
78
-
79
- ## **Supported Source Tables**
80
-
81
- ### **`currencies`**
82
- - **Description**: Fetches a list of available currencies.
83
- - **Columns**:
84
- - `currency_code`: The ISO 4217 currency code (e.g., `USD`, `EUR`).
85
- - `currency_name`: The name of the currency (e.g., `US Dollar`, `Euro`).
86
- - **Primary Key**: `currency_code`
87
-
88
- ---
89
-
90
- ### **`latest`**
91
- - **Description**: Fetches the latest exchange rates.
92
- - **Columns**:
93
- - `date`: The date of the exchange rates.
94
- - `currency_code`: The ISO 4217 currency code (e.g., `USD`, `EUR`).
95
- - `rate`: The exchange rate relative to the base currency.
96
- - `base_currency`: The base currency used to calculate the exchange rate.
97
- - **Primary Key**: Composite key of `date`, `currency_code` and `base_currency`.
98
- - **Notes**:
99
- - The base currency (e.g., `EUR`) is included with a rate of `1.0`.
100
-
101
- ---
102
-
103
- ### **`exchange_rates`**
104
- - **Description**: Fetches historical exchange rates for a specified date range.
105
- - **Columns**:
106
- - `date`: The date of the exchange rates.
107
- - `currency_code`: The ISO 4217 currency code (e.g., `USD`, `EUR`).
108
- - `rate`: The exchange rate relative to the base currency.
109
- - `base_currency`: The base currency used to calculate the exchange rate.
110
- - **Primary Key**: Composite key of `date`, `currency_code` and `base_currency`.
111
- - **Notes**:
112
- - An optional start and end date can be added via the arguments `--interval-start` and optionally `--interval-end` to define the date range (see examples below). If no start date is specified, the date will default today's date (and thus return the latest exchange rates).
113
- - If a start date but no end date is specified, then the end date will default to today's date and ingestr will retrieve data up until the latest published data.
114
- - Note that the [Frankfurter API](https://www.frankfurter.dev/) only publishes updates Monday-Friday. If the given date is on the weekend, the date will default to the previous Friday. The source is however implemented in ingestr in such a way as to avoid duplicating rows of data in this case (see [Incremental Loading - Replace](https://bruin-data.github.io/ingestr/getting-started/incremental-loading.html)).
115
-
116
- #### **Example Table: Handling Weekend Dates**
117
- Here `--interval-start` is set to a weekend date (e.g., `2025-03-29` -- a Saturday). `--interval-end` is set to a the following Monday (`2025-03-31`).
118
-
119
- `--interval-start` defaults to the previous Friday (`2025-03-28`) and the next data is from the following Monday (for simplicity, only a subset of currencies is shown below):
120
-
121
- | **date** | **currency_code** | **rate** | **base_currency** |
122
- |--------------|-------------------|----------|-------------------|
123
- | 2025-03-28 | EUR | 1.0 | EUR |
124
- | 2025-03-28 | USD | 1.0783 | EUR |
125
- | 2025-03-28 | GBP | 0.8571 | EUR |
126
- | 2025-03-31 | EUR | 1.0 | EUR |
127
- | 2025-03-31 | USD | 1.0783 | EUR |
128
- | 2025-03-31 | GBP | 0.8571 | EUR |
129
-
130
-
131
- ---
132
-
133
- ## **Examples**
134
-
135
- ### **1. Fetch the Latest Exchange Rates with GBP as Base Currency**
136
- ```bash
137
- ingestr ingest \
138
- --source-uri 'frankfurter://?base=GBP' \
139
- --source-table 'latest' \
140
- --dest-uri 'duckdb.db' \
141
- --dest-table 'schema.latest_new_scheme'
142
- ```
143
-
144
- ---
145
-
146
- ### **2. Fetch Historical Exchange Rates with USD as Default Base Currency**
147
- ```bash
148
- ingestr ingest \
149
- --source-uri 'frankfurter://' \
150
- --interval-start '2025-03-01' \
151
- --interval-end '2025-03-10' \
152
- --source-table 'exchange_rates' \
153
- --dest-uri 'duckdb.db' \
154
- --dest-table 'schema.exchange_rates'
155
- ```
156
-
157
- ---
158
-
159
- ### **3. Fetch Currency Metadata**
160
- ```bash
161
- ingestr ingest \
162
- --source-uri 'frankfurter://' \
163
- --source-table 'currencies' \
164
- --dest-uri 'duckdb.db' \
165
- --dest-table 'schema.currencies'
166
- ```
167
-
168
- ---
169
-
170
- ## **Notes**
171
- - Ensure that the destination database (`--dest-uri`) is accessible and writable.
172
- - The `--interval-start` and `--interval-end` parameters are only applicable for the `exchange_rates` table.
173
- - The `latest` table always fetches the most recent exchange rates and ignores date parameters.