ingestr 0.13.54__tar.gz → 0.13.56__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 (301) hide show
  1. {ingestr-0.13.54 → ingestr-0.13.56}/PKG-INFO +1 -1
  2. {ingestr-0.13.54 → ingestr-0.13.56}/docs/.vitepress/config.mjs +1 -0
  3. ingestr-0.13.56/docs/supported-sources/facebook-ads.md +202 -0
  4. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/s3.md +46 -0
  5. ingestr-0.13.56/docs/supported-sources/trustpilot.md +35 -0
  6. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/blob.py +24 -0
  7. ingestr-0.13.56/ingestr/src/buildinfo.py +1 -0
  8. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/facebook_ads/__init__.py +18 -8
  9. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/facebook_ads/helpers.py +2 -4
  10. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/facebook_ads/settings.py +2 -0
  11. ingestr-0.13.56/ingestr/src/facebook_ads/utils.py +39 -0
  12. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/factory.py +2 -0
  13. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/sources.py +128 -30
  14. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/stripe_analytics/__init__.py +4 -2
  15. ingestr-0.13.56/ingestr/src/trustpilot/__init__.py +48 -0
  16. ingestr-0.13.56/ingestr/src/trustpilot/client.py +48 -0
  17. {ingestr-0.13.54 → ingestr-0.13.56}/package-lock.json +3 -3
  18. {ingestr-0.13.54 → ingestr-0.13.56}/requirements_arm64.txt +3 -3
  19. ingestr-0.13.54/docs/supported-sources/facebook-ads.md +0 -51
  20. ingestr-0.13.54/ingestr/src/buildinfo.py +0 -1
  21. {ingestr-0.13.54 → ingestr-0.13.56}/.dockerignore +0 -0
  22. {ingestr-0.13.54 → ingestr-0.13.56}/.githooks/pre-commit-hook.sh +0 -0
  23. {ingestr-0.13.54 → ingestr-0.13.56}/.github/workflows/deploy-docs.yml +0 -0
  24. {ingestr-0.13.54 → ingestr-0.13.56}/.github/workflows/release.yml +0 -0
  25. {ingestr-0.13.54 → ingestr-0.13.56}/.github/workflows/secrets-scan.yml +0 -0
  26. {ingestr-0.13.54 → ingestr-0.13.56}/.github/workflows/tests.yml +0 -0
  27. {ingestr-0.13.54 → ingestr-0.13.56}/.gitignore +0 -0
  28. {ingestr-0.13.54 → ingestr-0.13.56}/.gitleaksignore +0 -0
  29. {ingestr-0.13.54 → ingestr-0.13.56}/.python-version +0 -0
  30. {ingestr-0.13.54 → ingestr-0.13.56}/.vale.ini +0 -0
  31. {ingestr-0.13.54 → ingestr-0.13.56}/Dockerfile +0 -0
  32. {ingestr-0.13.54 → ingestr-0.13.56}/LICENSE.md +0 -0
  33. {ingestr-0.13.54 → ingestr-0.13.56}/Makefile +0 -0
  34. {ingestr-0.13.54 → ingestr-0.13.56}/README.md +0 -0
  35. {ingestr-0.13.54 → ingestr-0.13.56}/docs/.vitepress/theme/custom.css +0 -0
  36. {ingestr-0.13.54 → ingestr-0.13.56}/docs/.vitepress/theme/index.js +0 -0
  37. {ingestr-0.13.54 → ingestr-0.13.56}/docs/commands/example-uris.md +0 -0
  38. {ingestr-0.13.54 → ingestr-0.13.56}/docs/commands/ingest.md +0 -0
  39. {ingestr-0.13.54 → ingestr-0.13.56}/docs/getting-started/core-concepts.md +0 -0
  40. {ingestr-0.13.54 → ingestr-0.13.56}/docs/getting-started/incremental-loading.md +0 -0
  41. {ingestr-0.13.54 → ingestr-0.13.56}/docs/getting-started/quickstart.md +0 -0
  42. {ingestr-0.13.54 → ingestr-0.13.56}/docs/getting-started/telemetry.md +0 -0
  43. {ingestr-0.13.54 → ingestr-0.13.56}/docs/index.md +0 -0
  44. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/applovin_max.png +0 -0
  45. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/athena.png +0 -0
  46. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/clickhouse_img.png +0 -0
  47. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/cratedb-source.png +0 -0
  48. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/freshdesk_ingestion.png +0 -0
  49. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/gcp_spanner_ingestion.png +0 -0
  50. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/github.png +0 -0
  51. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/google_analytics_realtime_report.png +0 -0
  52. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/googleanalytics.png +0 -0
  53. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/ingestion_elasticsearch_img.png +0 -0
  54. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/kinesis.bigquery.png +0 -0
  55. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/linkedin_ads.png +0 -0
  56. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/mixpanel_ingestion.png +0 -0
  57. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/personio.png +0 -0
  58. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/personio_duckdb.png +0 -0
  59. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/phantombuster.png +0 -0
  60. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/pipedrive.png +0 -0
  61. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/quickbook_ingestion.png +0 -0
  62. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/sftp.png +0 -0
  63. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/stripe_postgres.png +0 -0
  64. {ingestr-0.13.54 → ingestr-0.13.56}/docs/media/tiktok.png +0 -0
  65. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/adjust.md +0 -0
  66. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/airtable.md +0 -0
  67. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/applovin.md +0 -0
  68. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/applovin_max.md +0 -0
  69. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/appsflyer.md +0 -0
  70. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/appstore.md +0 -0
  71. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/asana.md +0 -0
  72. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/athena.md +0 -0
  73. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/attio.md +0 -0
  74. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/bigquery.md +0 -0
  75. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/chess.md +0 -0
  76. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/clickhouse.md +0 -0
  77. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/cratedb.md +0 -0
  78. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/csv.md +0 -0
  79. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/custom_queries.md +0 -0
  80. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/databricks.md +0 -0
  81. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/db2.md +0 -0
  82. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/duckdb.md +0 -0
  83. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/dynamodb.md +0 -0
  84. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/elasticsearch.md +0 -0
  85. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/frankfurter.md +0 -0
  86. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/freshdesk.md +0 -0
  87. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/gcs.md +0 -0
  88. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/github.md +0 -0
  89. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/google-ads.md +0 -0
  90. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/google_analytics.md +0 -0
  91. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/gorgias.md +0 -0
  92. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/gsheets.md +0 -0
  93. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/hubspot.md +0 -0
  94. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/kafka.md +0 -0
  95. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/kinesis.md +0 -0
  96. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/klaviyo.md +0 -0
  97. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/linkedin_ads.md +0 -0
  98. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/mixpanel.md +0 -0
  99. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/mongodb.md +0 -0
  100. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/mssql.md +0 -0
  101. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/mysql.md +0 -0
  102. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/notion.md +0 -0
  103. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/oracle.md +0 -0
  104. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/personio.md +0 -0
  105. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/phantombuster.md +0 -0
  106. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/pipedrive.md +0 -0
  107. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/postgres.md +0 -0
  108. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/quickbooks.md +0 -0
  109. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/redshift.md +0 -0
  110. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/salesforce.md +0 -0
  111. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/sap-hana.md +0 -0
  112. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/sftp.md +0 -0
  113. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/shopify.md +0 -0
  114. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/slack.md +0 -0
  115. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/smartsheets.md +0 -0
  116. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/snowflake.md +0 -0
  117. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/solidgate.md +0 -0
  118. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/spanner.md +0 -0
  119. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/sqlite.md +0 -0
  120. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/stripe.md +0 -0
  121. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/tiktok-ads.md +0 -0
  122. {ingestr-0.13.54 → ingestr-0.13.56}/docs/supported-sources/zendesk.md +0 -0
  123. {ingestr-0.13.54 → ingestr-0.13.56}/docs/tutorials/load-kinesis-bigquery.md +0 -0
  124. {ingestr-0.13.54 → ingestr-0.13.56}/docs/tutorials/load-personio-duckdb.md +0 -0
  125. {ingestr-0.13.54 → ingestr-0.13.56}/docs/tutorials/load-stripe-postgres.md +0 -0
  126. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/conftest.py +0 -0
  127. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/main.py +0 -0
  128. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/.gitignore +0 -0
  129. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/adjust/__init__.py +0 -0
  130. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/adjust/adjust_helpers.py +0 -0
  131. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/airtable/__init__.py +0 -0
  132. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/applovin/__init__.py +0 -0
  133. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/applovin_max/__init__.py +0 -0
  134. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/appsflyer/__init__.py +0 -0
  135. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/appsflyer/client.py +0 -0
  136. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/appstore/__init__.py +0 -0
  137. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/appstore/client.py +0 -0
  138. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/appstore/errors.py +0 -0
  139. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/appstore/models.py +0 -0
  140. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/appstore/resources.py +0 -0
  141. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/arrow/__init__.py +0 -0
  142. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/asana_source/__init__.py +0 -0
  143. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/asana_source/helpers.py +0 -0
  144. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/asana_source/settings.py +0 -0
  145. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/attio/__init__.py +0 -0
  146. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/attio/helpers.py +0 -0
  147. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/chess/__init__.py +0 -0
  148. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/chess/helpers.py +0 -0
  149. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/chess/settings.py +0 -0
  150. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/collector/spinner.py +0 -0
  151. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/destinations.py +0 -0
  152. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/dynamodb/__init__.py +0 -0
  153. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/elasticsearch/__init__.py +0 -0
  154. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/errors.py +0 -0
  155. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/facebook_ads/exceptions.py +0 -0
  156. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/filesystem/__init__.py +0 -0
  157. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/filesystem/helpers.py +0 -0
  158. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/filesystem/readers.py +0 -0
  159. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/filters.py +0 -0
  160. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/frankfurter/__init__.py +0 -0
  161. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/frankfurter/helpers.py +0 -0
  162. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/freshdesk/__init__.py +0 -0
  163. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/freshdesk/freshdesk_client.py +0 -0
  164. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/freshdesk/settings.py +0 -0
  165. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/github/__init__.py +0 -0
  166. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/github/helpers.py +0 -0
  167. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/github/queries.py +0 -0
  168. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/github/settings.py +0 -0
  169. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/google_ads/__init__.py +0 -0
  170. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/google_ads/field.py +0 -0
  171. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/google_ads/metrics.py +0 -0
  172. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/google_ads/predicates.py +0 -0
  173. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/google_ads/reports.py +0 -0
  174. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/google_analytics/__init__.py +0 -0
  175. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/google_analytics/helpers.py +0 -0
  176. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/google_sheets/README.md +0 -0
  177. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/google_sheets/__init__.py +0 -0
  178. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
  179. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
  180. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
  181. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/gorgias/__init__.py +0 -0
  182. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/gorgias/helpers.py +0 -0
  183. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/http_client.py +0 -0
  184. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/hubspot/__init__.py +0 -0
  185. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/hubspot/helpers.py +0 -0
  186. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/hubspot/settings.py +0 -0
  187. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/kafka/__init__.py +0 -0
  188. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/kafka/helpers.py +0 -0
  189. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/kinesis/__init__.py +0 -0
  190. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/kinesis/helpers.py +0 -0
  191. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/klaviyo/__init__.py +0 -0
  192. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/klaviyo/client.py +0 -0
  193. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/klaviyo/helpers.py +0 -0
  194. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/linkedin_ads/__init__.py +0 -0
  195. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/linkedin_ads/dimension_time_enum.py +0 -0
  196. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/linkedin_ads/helpers.py +0 -0
  197. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/loader.py +0 -0
  198. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/mixpanel/__init__.py +0 -0
  199. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/mixpanel/client.py +0 -0
  200. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/mongodb/__init__.py +0 -0
  201. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/mongodb/helpers.py +0 -0
  202. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/notion/__init__.py +0 -0
  203. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/notion/helpers/__init__.py +0 -0
  204. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/notion/helpers/client.py +0 -0
  205. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/notion/helpers/database.py +0 -0
  206. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/notion/settings.py +0 -0
  207. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/partition.py +0 -0
  208. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/personio/__init__.py +0 -0
  209. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/personio/helpers.py +0 -0
  210. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/phantombuster/__init__.py +0 -0
  211. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/phantombuster/client.py +0 -0
  212. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/pipedrive/__init__.py +0 -0
  213. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/pipedrive/helpers/__init__.py +0 -0
  214. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/pipedrive/helpers/custom_fields_munger.py +0 -0
  215. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/pipedrive/helpers/pages.py +0 -0
  216. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/pipedrive/settings.py +0 -0
  217. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/pipedrive/typing.py +0 -0
  218. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/quickbooks/__init__.py +0 -0
  219. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/resource.py +0 -0
  220. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/salesforce/__init__.py +0 -0
  221. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/salesforce/helpers.py +0 -0
  222. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/shopify/__init__.py +0 -0
  223. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/shopify/exceptions.py +0 -0
  224. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/shopify/helpers.py +0 -0
  225. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/shopify/settings.py +0 -0
  226. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/slack/__init__.py +0 -0
  227. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/slack/helpers.py +0 -0
  228. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/slack/settings.py +0 -0
  229. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/smartsheets/__init__.py +0 -0
  230. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/solidgate/__init__.py +0 -0
  231. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/solidgate/helpers.py +0 -0
  232. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/sql_database/__init__.py +0 -0
  233. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/sql_database/callbacks.py +0 -0
  234. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/stripe_analytics/helpers.py +0 -0
  235. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/stripe_analytics/settings.py +0 -0
  236. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/table_definition.py +0 -0
  237. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/telemetry/event.py +0 -0
  238. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/testdata/fakebqcredentials.json +0 -0
  239. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/tiktok_ads/__init__.py +0 -0
  240. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/tiktok_ads/tiktok_helpers.py +0 -0
  241. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/time.py +0 -0
  242. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/version.py +0 -0
  243. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/zendesk/__init__.py +0 -0
  244. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/zendesk/helpers/__init__.py +0 -0
  245. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
  246. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/zendesk/helpers/credentials.py +0 -0
  247. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
  248. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/src/zendesk/settings.py +0 -0
  249. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/testdata/.gitignore +0 -0
  250. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/testdata/create_replace.csv +0 -0
  251. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/testdata/delete_insert_expected.csv +0 -0
  252. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/testdata/delete_insert_part1.csv +0 -0
  253. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/testdata/delete_insert_part2.csv +0 -0
  254. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/testdata/merge_expected.csv +0 -0
  255. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/testdata/merge_part1.csv +0 -0
  256. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/testdata/merge_part2.csv +0 -0
  257. {ingestr-0.13.54 → ingestr-0.13.56}/ingestr/tests/unit/test_smartsheets.py +0 -0
  258. {ingestr-0.13.54 → ingestr-0.13.56}/package.json +0 -0
  259. {ingestr-0.13.54 → ingestr-0.13.56}/pyproject.toml +0 -0
  260. {ingestr-0.13.54 → ingestr-0.13.56}/requirements-dev.txt +0 -0
  261. {ingestr-0.13.54 → ingestr-0.13.56}/requirements.in +0 -0
  262. {ingestr-0.13.54 → ingestr-0.13.56}/requirements.txt +0 -0
  263. {ingestr-0.13.54 → ingestr-0.13.56}/resources/demo.gif +0 -0
  264. {ingestr-0.13.54 → ingestr-0.13.56}/resources/demo.tape +0 -0
  265. {ingestr-0.13.54 → ingestr-0.13.56}/resources/ingestr.svg +0 -0
  266. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/AMPM.yml +0 -0
  267. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Acronyms.yml +0 -0
  268. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Colons.yml +0 -0
  269. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Contractions.yml +0 -0
  270. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/DateFormat.yml +0 -0
  271. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Ellipses.yml +0 -0
  272. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/EmDash.yml +0 -0
  273. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Exclamation.yml +0 -0
  274. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/FirstPerson.yml +0 -0
  275. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Gender.yml +0 -0
  276. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/GenderBias.yml +0 -0
  277. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/HeadingPunctuation.yml +0 -0
  278. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Headings.yml +0 -0
  279. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Latin.yml +0 -0
  280. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/LyHyphens.yml +0 -0
  281. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/OptionalPlurals.yml +0 -0
  282. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Ordinal.yml +0 -0
  283. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/OxfordComma.yml +0 -0
  284. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Parens.yml +0 -0
  285. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Passive.yml +0 -0
  286. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Periods.yml +0 -0
  287. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Quotes.yml +0 -0
  288. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Ranges.yml +0 -0
  289. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Semicolons.yml +0 -0
  290. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Slang.yml +0 -0
  291. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Spacing.yml +0 -0
  292. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Spelling.yml +0 -0
  293. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Units.yml +0 -0
  294. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/We.yml +0 -0
  295. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/Will.yml +0 -0
  296. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/WordList.yml +0 -0
  297. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/meta.json +0 -0
  298. {ingestr-0.13.54 → ingestr-0.13.56}/styles/Google/vocab.txt +0 -0
  299. {ingestr-0.13.54 → ingestr-0.13.56}/styles/bruin/Ingestr.yml +0 -0
  300. {ingestr-0.13.54 → ingestr-0.13.56}/styles/config/vocabularies/bruin/accept.txt +0 -0
  301. {ingestr-0.13.54 → ingestr-0.13.56}/test.env.template +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ingestr
3
- Version: 0.13.54
3
+ Version: 0.13.56
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
@@ -123,6 +123,7 @@ export default defineConfig({
123
123
  },
124
124
  { text: "Frankfurter", link: "/supported-sources/frankfurter.md" },
125
125
  { text: "Freshdesk", link: "/supported-sources/freshdesk.md" },
126
+ { text: "Trustpilot", link: "/supported-sources/trustpilot.md" },
126
127
  { text: "Google Cloud Storage (GCS)", link: "/supported-sources/gcs.md" },
127
128
  { text: "Google Analytics", link: "/supported-sources/google_analytics.md" },
128
129
  { text: "Google Ads", link: "/supported-sources/google-ads.md" },
@@ -0,0 +1,202 @@
1
+ # Facebook Ads
2
+
3
+ Facebook Ads is the advertising platform that helps users to create targeted ads on Facebook, Instagram and Messenger.
4
+
5
+ ingestr supports Facebook Ads as a source.
6
+
7
+ ## URI format
8
+
9
+ The URI format for Facebook Ads is as follows:
10
+
11
+ ```plaintext
12
+ facebookads://?access_token=<access_token>&account_id=<account_id>
13
+ ```
14
+
15
+ URI parameters:
16
+
17
+ - `access_token` is associated with Business Facebook App.
18
+ - `account_id` is associated with Ad manager.
19
+
20
+ Both are used for authentication with Facebook Ads API.
21
+
22
+ The URI is used to connect to Facebook Ads API for extracting data.
23
+
24
+ ## Setting up a Facebook Ads Integration
25
+
26
+ Facebook Ads requires a few steps to set up an integration, please follow the guide dltHub [has built here](https://dlthub.com/docs/dlt-ecosystem/verified-sources/facebook_ads#setup-guide).
27
+
28
+ Once you complete the guide, you should have an access token and an Account ID. Let's say your `access_token` is `abcdef` and `account_id` is `1234`, here's a sample command that will copy the data from Facebook Ads into a DuckDB database:
29
+
30
+ ```sh
31
+ ingestr ingest \
32
+ --source-uri 'facebookads://?access_token=easdyh&account_id=1234' \
33
+ --source-table 'campaigns' \
34
+ --dest-uri 'duckdb:///facebook.duckdb' \
35
+ --dest-table 'dest.campaigns'
36
+ ```
37
+
38
+ The result of this command will be a table in the `facebook.duckdb` database.
39
+
40
+ ## Tables
41
+
42
+ Facebook Ads source allows ingesting the following sources into separate tables:
43
+
44
+ - `campaigns`: Retrieves campaign data with fields:
45
+ - `id`
46
+ - `updated_time`
47
+ - `created_time`
48
+ - `name`
49
+ - `status`
50
+ - `effective_status`
51
+ - `objective`
52
+ - `start_time`
53
+ - `stop_time`
54
+ - `daily_budget`
55
+ - `lifetime_budget`
56
+
57
+ - `ad_sets`: Retrieves ad set data with fields:
58
+ - `id`
59
+ - `updated_time`
60
+ - `created_time`
61
+ - `name`
62
+ - `status`
63
+ - `effective_status`
64
+ - `campaign_id`
65
+ - `start_time`
66
+ - `end_time`
67
+ - `daily_budget`
68
+ - `lifetime_budget`
69
+ - `optimization_goal`
70
+ - `promoted_object`
71
+ - `billing_event`
72
+ - `bid_amount`
73
+ - `bid_strategy`
74
+ - `targeting`
75
+
76
+ - `leads`: Retrieves lead data with fields:
77
+ - `id`
78
+ - `created_time`
79
+ - `ad_id`
80
+ - `ad_name`
81
+ - `adset_id`
82
+ - `adset_name`
83
+ - `campaign_id`
84
+ - `campaign_name`
85
+ - `form_id`
86
+ - `field_data`
87
+
88
+ - `ads_creatives`: Retrieves ad creative data with fields:
89
+ - `id`
90
+ - `name`
91
+ - `status`
92
+ - `thumbnail_url`
93
+ - `object_story_spec`
94
+ - `effective_object_story_id`
95
+ - `call_to_action_type`
96
+ - `object_type`
97
+ - `template_url`
98
+ - `url_tags`
99
+ - `instagram_actor_id`
100
+ - `product_set_id`
101
+
102
+ - `ads`: Retrieves ad data with fields:
103
+ - `id`
104
+ - `updated_time`
105
+ - `created_time`
106
+ - `name`
107
+ - `status`
108
+ - `effective_status`
109
+ - `adset_id`
110
+ - `campaign_id`
111
+ - `creative`
112
+ - `targeting`
113
+ - `tracking_specs`
114
+ - `conversion_specs`
115
+
116
+ - `facebook_insights`: Retrieves insights data with fields:
117
+ - `campaign_id`
118
+ - `adset_id`
119
+ - `ad_id`
120
+ - `date_start`
121
+ - `date_stop`
122
+ - `reach`
123
+ - `impressions`
124
+ - `frequency`
125
+ - `clicks`
126
+ - `unique_clicks`
127
+ - `ctr`
128
+ - `unique_ctr`
129
+ - `cpc`
130
+ - `cpm`
131
+ - `cpp`
132
+ - `spend`
133
+ - `actions`
134
+ - `action_values`
135
+ - `cost_per_action_type`
136
+ - `website_ctr`
137
+ - `account_currency`
138
+ - `ad_click_actions`
139
+ - `ad_name`
140
+ - `adset_name`
141
+ - `campaign_name`
142
+ - `country`
143
+ - `dma`
144
+ - `full_view_impressions`
145
+ - `full_view_reach`
146
+ - `inline_link_click_ctr`
147
+ - `outbound_clicks`
148
+ - `social_spend`
149
+ - `conversions`
150
+ - `video_thruplay_watched_actions`
151
+
152
+ Use these as `--source-table` parameter in the `ingestr ingest` command.
153
+
154
+ ### Facebook Insights Custom Configuration
155
+
156
+ The `facebook_insights` table supports advanced configuration for breakdowns and custom metrics:
157
+
158
+ #### Format Options
159
+
160
+ 1. **Default usage**: `facebook_insights`
161
+ - Uses default breakdown and default fields
162
+
163
+ 2. **Custom breakdown**: `facebook_insights:breakdown_type`
164
+ - Uses specified breakdown with default fields
165
+
166
+ 3. **Custom breakdown + metrics**: `facebook_insights:breakdown_type:metric1,metric2,metric3`
167
+ - Uses specified breakdown with custom metrics
168
+
169
+ #### Available Breakdown Types
170
+
171
+ - `ads_insights` (default)
172
+ - `ads_insights_age_and_gender`
173
+ - `ads_insights_country`
174
+ - `ads_insights_platform_and_device`
175
+ - `ads_insights_region`
176
+ - `ads_insights_dma`
177
+ - `ads_insights_hourly_advertiser`
178
+
179
+ #### Examples
180
+
181
+ ```sh
182
+ # Default facebook_insights
183
+ ingestr ingest \
184
+ --source-uri 'facebookads://?access_token=easdyh&account_id=1234' \
185
+ --source-table 'facebook_insights' \
186
+ --dest-uri 'duckdb:///facebook.duckdb' \
187
+ --dest-table 'dest.insights'
188
+
189
+ # Age and gender breakdown with default metrics
190
+ ingestr ingest \
191
+ --source-uri 'facebookads://?access_token=easdyh&account_id=1234' \
192
+ --source-table 'facebook_insights:ads_insights_age_and_gender' \
193
+ --dest-uri 'duckdb:///facebook.duckdb' \
194
+ --dest-table 'dest.insights_demographics'
195
+
196
+ # Country breakdown with custom metrics
197
+ ingestr ingest \
198
+ --source-uri 'facebookads://?access_token=easdyh&account_id=1234' \
199
+ --source-table 'facebook_insights:ads_insights_country:impressions,clicks,spend,reach,cpm,ctr' \
200
+ --dest-uri 'duckdb:///facebook.duckdb' \
201
+ --dest-table 'dest.insights_by_country'
202
+ ```
@@ -134,3 +134,49 @@ The `<file-glob-pattern>` in the `--source-table` argument allows for flexible f
134
134
  | `bucket/myFolder/**/*.jsonl` | Retrieves all JSONL files recursively from the `myFolder` directory and its subdirectories in `s3://bucket`. |
135
135
  | `bucket/myFolder/mySubFolder/users.parquet` | Retrieves the specific `users.parquet` file from the `myFolder/mySubFolder/` path in `s3://bucket`. |
136
136
  | `bucket/employees.jsonl` | Retrieves the `employees.jsonl` file located at the root level of the `s3://bucket`. |
137
+
138
+
139
+ ### Working with compressed files
140
+
141
+ `ingestr` automatically detects and handles gzipped files in your S3 bucket. You can load data from compressed files with the `.gz` extension without any additional configuration.
142
+
143
+ For example, to load data from a gzipped CSV file:
144
+
145
+ ```sh
146
+ ingestr ingest \
147
+ --source-uri 's3://?access_key_id=AKC3YOW7E&secret_access_key=XCtkpL5B' \
148
+ --source-table 'my_bucket/logs/event-data.csv.gz' \
149
+ --dest-uri duckdb:///compressed_data.duckdb \
150
+ --dest-table 'logs.events'
151
+ ```
152
+
153
+ You can also use glob patterns to load multiple compressed files:
154
+
155
+ ```sh
156
+ ingestr ingest \
157
+ --source-uri 's3://?access_key_id=AKC3YOW7E&secret_access_key=XCtkpL5B' \
158
+ --source-table 'my_bucket/logs/**/*.csv.gz' \
159
+ --dest-uri duckdb:///compressed_data.duckdb \
160
+ --dest-table 'logs.events'
161
+ ```
162
+
163
+ ### File type hinting
164
+
165
+ If your files are properly encoded but lack the correct file extension (CSV, JSONL, or Parquet), you can provide a file type hint to inform `ingestr` about the format of the files. This is done by appending a fragment identifier (`#format`) to the end of the path in your `--source-table` parameter.
166
+
167
+ For example, if you have JSONL-formatted log files stored in S3 with a non-standard extension:
168
+
169
+ ```
170
+ --source-table "my_bucket/logs/event-data#jsonl"
171
+ ```
172
+
173
+ This tells `ingestr` to process the files as JSONL, regardless of their actual extension.
174
+
175
+ Supported format hints include:
176
+ - `#csv` - For comma-separated values files
177
+ - `#jsonl` - For line-delimited JSON files
178
+ - `#parquet` - For Parquet format files
179
+
180
+ ::: tip
181
+ File type hinting works with `gzip` compressed files as well.
182
+ :::
@@ -0,0 +1,35 @@
1
+ # Trustpilot
2
+
3
+ [Trustpilot](https://www.trustpilot.com/) provides a platform for collecting and
4
+ sharing customer reviews.
5
+
6
+ ingestr supports Trustpilot as a source.
7
+
8
+ ## URI format
9
+
10
+ The URI format for Trustpilot is:
11
+
12
+ ```
13
+ trustpilot://<business_unit_id>?api_key=<api_key>
14
+ ```
15
+
16
+ URI parameters:
17
+ - `api_key`: Your Trustpilot API key.
18
+ - `business_unit_id`: Identifier of the business unit whose reviews you want to fetch.
19
+
20
+ ## Example usage
21
+
22
+ Assuming your `business_unit_id` is `123` and your API key is `key_abc`, you can ingest reviews into DuckDB using:
23
+
24
+ ```bash
25
+ ingestr ingest --source-uri 'trustpilot://123?api_key=key_abc' --source-table 'reviews' --dest-uri duckdb:///trustpilot.duckdb --dest-table 'dest.reviews'
26
+ ```
27
+
28
+ ## Tables
29
+
30
+ Currently the Trustpilot source exposes the following table:
31
+
32
+ | Name | Description |
33
+ | ------- | ------------------------------------------- |
34
+ | reviews | Customer reviews for the specified business |
35
+
@@ -6,6 +6,10 @@ BucketName: TypeAlias = str
6
6
  FileGlob: TypeAlias = str
7
7
 
8
8
 
9
+ class UnsupportedEndpointError(Exception):
10
+ pass
11
+
12
+
9
13
  def parse_uri(uri: ParseResult, table: str) -> Tuple[BucketName, FileGlob]:
10
14
  """
11
15
  parse the URI of a blob storage and
@@ -50,3 +54,23 @@ def parse_uri(uri: ParseResult, table: str) -> Tuple[BucketName, FileGlob]:
50
54
  return "", parts[0]
51
55
 
52
56
  return parts[0], parts[1]
57
+
58
+
59
+ def parse_endpoint(path: str) -> str:
60
+ """
61
+ Parse the endpoint kind from the URI.
62
+
63
+ kind is a file format. one of [csv, jsonl, parquet]
64
+ """
65
+ file_extension = path.split(".")[-1]
66
+ if file_extension == "gz":
67
+ file_extension = path.split(".")[-2]
68
+ if file_extension == "csv":
69
+ endpoint = "read_csv"
70
+ elif file_extension == "jsonl":
71
+ endpoint = "read_jsonl"
72
+ elif file_extension == "parquet":
73
+ endpoint = "read_parquet"
74
+ else:
75
+ raise UnsupportedEndpointError(f"Unsupported file format: {file_extension}")
76
+ return endpoint
@@ -0,0 +1 @@
1
+ version = "v0.13.56"
@@ -116,6 +116,8 @@ def facebook_insights_source(
116
116
  batch_size: int = 50,
117
117
  request_timeout: int = 300,
118
118
  app_api_version: str = None,
119
+ start_date: pendulum.DateTime | None = None,
120
+ end_date: pendulum.DateTime | None = None,
119
121
  ) -> DltResource:
120
122
  """Incrementally loads insight reports with defined granularity level, fields, breakdowns etc.
121
123
 
@@ -148,27 +150,32 @@ def facebook_insights_source(
148
150
  account_id, access_token, request_timeout, app_api_version
149
151
  )
150
152
 
151
- # we load with a defined lag
152
- initial_load_start_date = pendulum.today().subtract(days=initial_load_past_days)
153
- initial_load_start_date_str = initial_load_start_date.isoformat()
153
+ if start_date is None:
154
+ start_date = pendulum.today().subtract(days=initial_load_past_days)
155
+
156
+ columns = {}
157
+ for field in fields:
158
+ if field in INSIGHT_FIELDS_TYPES:
159
+ columns[field] = INSIGHT_FIELDS_TYPES[field]
154
160
 
155
161
  @dlt.resource(
156
162
  primary_key=INSIGHTS_PRIMARY_KEY,
157
163
  write_disposition="merge",
158
- columns=INSIGHT_FIELDS_TYPES,
164
+ columns=columns,
159
165
  )
160
166
  def facebook_insights(
161
167
  date_start: dlt.sources.incremental[str] = dlt.sources.incremental(
162
168
  "date_start",
163
- initial_value=initial_load_start_date_str,
169
+ initial_value=start_date.isoformat(),
170
+ end_value=end_date.isoformat() if end_date else None,
164
171
  range_end="closed",
165
172
  range_start="closed",
173
+ lag=attribution_window_days_lag * 24 * 60 * 60, # Convert days to seconds
166
174
  ),
167
175
  ) -> Iterator[TDataItems]:
168
- start_date = get_start_date(date_start, attribution_window_days_lag)
176
+ start_date = get_start_date(date_start)
169
177
  end_date = pendulum.now()
170
178
 
171
- # fetch insights in incremental day steps
172
179
  while start_date <= end_date:
173
180
  query = {
174
181
  "level": level,
@@ -193,7 +200,10 @@ def facebook_insights_source(
193
200
  }
194
201
  ],
195
202
  }
196
- job = execute_job(account.get_insights(params=query, is_async=True))
203
+ job = execute_job(
204
+ account.get_insights(params=query, is_async=True),
205
+ insights_max_async_sleep_seconds=10,
206
+ )
197
207
  yield list(map(process_report_item, job.get_result()))
198
208
  start_date = start_date.add(days=time_increment_days)
199
209
 
@@ -31,14 +31,13 @@ from .settings import (
31
31
 
32
32
  def get_start_date(
33
33
  incremental_start_date: dlt.sources.incremental[str],
34
- attribution_window_days_lag: int = 7,
35
34
  ) -> pendulum.DateTime:
36
35
  """
37
36
  Get the start date for incremental loading of Facebook Insights data.
38
37
  """
39
38
  start_date: pendulum.DateTime = ensure_pendulum_datetime(
40
39
  incremental_start_date.start_value
41
- ).subtract(days=attribution_window_days_lag)
40
+ )
42
41
 
43
42
  # facebook forgets insights so trim the lag and warn
44
43
  min_start_date = pendulum.today().subtract(
@@ -65,7 +64,6 @@ def process_report_item(item: AbstractObject) -> DictStrAny:
65
64
  for pki in INSIGHTS_PRIMARY_KEY:
66
65
  if pki not in d:
67
66
  d[pki] = "no_" + pki
68
-
69
67
  return d
70
68
 
71
69
 
@@ -138,7 +136,7 @@ def execute_job(
138
136
  ) -> AbstractCrudObject:
139
137
  status: str = None
140
138
  time_start = time.time()
141
- sleep_time = 10
139
+ sleep_time = 3
142
140
  while status != "Job Completed":
143
141
  duration = time.time() - time_start
144
142
  job = job.api_get()
@@ -112,6 +112,8 @@ DEFAULT_INSIGHT_FIELDS = (
112
112
  "social_spend",
113
113
  "spend",
114
114
  "website_ctr",
115
+ "conversions",
116
+ "video_thruplay_watched_actions",
115
117
  )
116
118
 
117
119
  TInsightsLevels = Literal["account", "campaign", "adset", "ad"]
@@ -0,0 +1,39 @@
1
+ from typing import Dict
2
+
3
+ import dlt
4
+ from dlt.common.configuration.inject import with_config
5
+ from dlt.sources.helpers import requests
6
+
7
+
8
+ @with_config(sections=("sources", "facebook_ads"))
9
+ def debug_access_token(
10
+ access_token: str = dlt.secrets.value,
11
+ client_id: str = dlt.secrets.value,
12
+ client_secret: str = dlt.secrets.value,
13
+ ) -> str:
14
+ """Debugs the `access_token` providing info on expiration time, scopes etc. If arguments are not provides, `dlt` will inject them from configuration"""
15
+ debug_url = f"https://graph.facebook.com/debug_token?input_token={access_token}&access_token={client_id}|{client_secret}"
16
+ response = requests.get(debug_url)
17
+ data: Dict[str, str] = response.json()
18
+
19
+ if "error" in data:
20
+ raise Exception(f"Error debugging token: {data['error']}")
21
+
22
+ return data["data"]
23
+
24
+
25
+ @with_config(sections=("sources", "facebook_ads"))
26
+ def get_long_lived_token(
27
+ access_token: str = dlt.secrets.value,
28
+ client_id: str = dlt.secrets.value,
29
+ client_secret: str = dlt.secrets.value,
30
+ ) -> str:
31
+ """Gets the long lived access token (60 days) from `access_token`. If arguments are not provides, `dlt` will inject them from configuration"""
32
+ exchange_url = f"https://graph.facebook.com/v13.0/oauth/access_token?grant_type=fb_exchange_token&client_id={client_id}&client_secret={client_secret}&fb_exchange_token={access_token}"
33
+ response = requests.get(exchange_url)
34
+ data: Dict[str, str] = response.json()
35
+
36
+ if "error" in data:
37
+ raise Exception(f"Error refreshing token: {data['error']}")
38
+
39
+ return data["access_token"]
@@ -64,6 +64,7 @@ from ingestr.src.sources import (
64
64
  SqlSource,
65
65
  StripeAnalyticsSource,
66
66
  TikTokSource,
67
+ TrustpilotSource,
67
68
  ZendeskSource,
68
69
  )
69
70
 
@@ -165,6 +166,7 @@ class SourceDestinationFactory:
165
166
  "pipedrive": PipedriveSource,
166
167
  "frankfurter": FrankfurterSource,
167
168
  "freshdesk": FreshdeskSource,
169
+ "trustpilot": TrustpilotSource,
168
170
  "phantombuster": PhantombusterSource,
169
171
  "elasticsearch": ElasticsearchSource,
170
172
  "attio": AttioSource,