ingestr 0.13.80__tar.gz → 0.13.81__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 (322) hide show
  1. {ingestr-0.13.80 → ingestr-0.13.81}/PKG-INFO +1 -1
  2. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/facebook-ads.md +63 -5
  3. ingestr-0.13.81/ingestr/src/buildinfo.py +1 -0
  4. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/facebook_ads/__init__.py +9 -15
  5. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/facebook_ads/helpers.py +46 -0
  6. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/linear/__init__.py +4 -2
  7. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/linear/helpers.py +6 -8
  8. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/sources.py +2 -19
  9. ingestr-0.13.80/ingestr/src/buildinfo.py +0 -1
  10. {ingestr-0.13.80 → ingestr-0.13.81}/.dlt/config.toml +0 -0
  11. {ingestr-0.13.80 → ingestr-0.13.81}/.dockerignore +0 -0
  12. {ingestr-0.13.80 → ingestr-0.13.81}/.githooks/pre-commit-hook.sh +0 -0
  13. {ingestr-0.13.80 → ingestr-0.13.81}/.github/workflows/deploy-docs.yml +0 -0
  14. {ingestr-0.13.80 → ingestr-0.13.81}/.github/workflows/release.yml +0 -0
  15. {ingestr-0.13.80 → ingestr-0.13.81}/.github/workflows/secrets-scan.yml +0 -0
  16. {ingestr-0.13.80 → ingestr-0.13.81}/.github/workflows/tests.yml +0 -0
  17. {ingestr-0.13.80 → ingestr-0.13.81}/.gitignore +0 -0
  18. {ingestr-0.13.80 → ingestr-0.13.81}/.gitleaksignore +0 -0
  19. {ingestr-0.13.80 → ingestr-0.13.81}/.python-version +0 -0
  20. {ingestr-0.13.80 → ingestr-0.13.81}/.vale.ini +0 -0
  21. {ingestr-0.13.80 → ingestr-0.13.81}/Dockerfile +0 -0
  22. {ingestr-0.13.80 → ingestr-0.13.81}/LICENSE.md +0 -0
  23. {ingestr-0.13.80 → ingestr-0.13.81}/Makefile +0 -0
  24. {ingestr-0.13.80 → ingestr-0.13.81}/README.md +0 -0
  25. {ingestr-0.13.80 → ingestr-0.13.81}/docs/.vitepress/config.mjs +0 -0
  26. {ingestr-0.13.80 → ingestr-0.13.81}/docs/.vitepress/theme/custom.css +0 -0
  27. {ingestr-0.13.80 → ingestr-0.13.81}/docs/.vitepress/theme/index.js +0 -0
  28. {ingestr-0.13.80 → ingestr-0.13.81}/docs/commands/example-uris.md +0 -0
  29. {ingestr-0.13.80 → ingestr-0.13.81}/docs/commands/ingest.md +0 -0
  30. {ingestr-0.13.80 → ingestr-0.13.81}/docs/getting-started/core-concepts.md +0 -0
  31. {ingestr-0.13.80 → ingestr-0.13.81}/docs/getting-started/incremental-loading.md +0 -0
  32. {ingestr-0.13.80 → ingestr-0.13.81}/docs/getting-started/quickstart.md +0 -0
  33. {ingestr-0.13.80 → ingestr-0.13.81}/docs/getting-started/telemetry.md +0 -0
  34. {ingestr-0.13.80 → ingestr-0.13.81}/docs/index.md +0 -0
  35. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/applovin_max.png +0 -0
  36. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/athena.png +0 -0
  37. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/clickhouse_img.png +0 -0
  38. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/clickup_ingestion.png +0 -0
  39. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/cratedb-destination.png +0 -0
  40. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/cratedb-source.png +0 -0
  41. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/freshdesk_ingestion.png +0 -0
  42. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/gcp_spanner_ingestion.png +0 -0
  43. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/github.png +0 -0
  44. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/google_analytics_realtime_report.png +0 -0
  45. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/googleanalytics.png +0 -0
  46. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/ingestion_elasticsearch_img.png +0 -0
  47. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/kinesis.bigquery.png +0 -0
  48. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/linear.png +0 -0
  49. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/linkedin_ads.png +0 -0
  50. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/mixpanel_ingestion.png +0 -0
  51. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/personio.png +0 -0
  52. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/personio_duckdb.png +0 -0
  53. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/phantombuster.png +0 -0
  54. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/pipedrive.png +0 -0
  55. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/quickbook_ingestion.png +0 -0
  56. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/sftp.png +0 -0
  57. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/stripe_postgres.png +0 -0
  58. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/tiktok.png +0 -0
  59. {ingestr-0.13.80 → ingestr-0.13.81}/docs/media/zoom_ingestion.png +0 -0
  60. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/adjust.md +0 -0
  61. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/airtable.md +0 -0
  62. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/applovin.md +0 -0
  63. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/applovin_max.md +0 -0
  64. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/appsflyer.md +0 -0
  65. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/appstore.md +0 -0
  66. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/asana.md +0 -0
  67. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/athena.md +0 -0
  68. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/attio.md +0 -0
  69. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/bigquery.md +0 -0
  70. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/chess.md +0 -0
  71. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/clickhouse.md +0 -0
  72. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/clickup.md +0 -0
  73. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/cratedb.md +0 -0
  74. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/csv.md +0 -0
  75. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/custom_queries.md +0 -0
  76. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/databricks.md +0 -0
  77. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/db2.md +0 -0
  78. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/duckdb.md +0 -0
  79. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/dynamodb.md +0 -0
  80. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/elasticsearch.md +0 -0
  81. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/frankfurter.md +0 -0
  82. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/freshdesk.md +0 -0
  83. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/gcs.md +0 -0
  84. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/github.md +0 -0
  85. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/google-ads.md +0 -0
  86. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/google_analytics.md +0 -0
  87. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/gorgias.md +0 -0
  88. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/gsheets.md +0 -0
  89. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/hubspot.md +0 -0
  90. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/influxdb.md +0 -0
  91. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/isoc-pulse.md +0 -0
  92. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/kafka.md +0 -0
  93. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/kinesis.md +0 -0
  94. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/klaviyo.md +0 -0
  95. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/linear.md +0 -0
  96. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/linkedin_ads.md +0 -0
  97. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/mixpanel.md +0 -0
  98. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/mongodb.md +0 -0
  99. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/motherduck.md +0 -0
  100. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/mssql.md +0 -0
  101. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/mysql.md +0 -0
  102. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/notion.md +0 -0
  103. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/oracle.md +0 -0
  104. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/personio.md +0 -0
  105. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/phantombuster.md +0 -0
  106. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/pinterest.md +0 -0
  107. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/pipedrive.md +0 -0
  108. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/postgres.md +0 -0
  109. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/quickbooks.md +0 -0
  110. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/redshift.md +0 -0
  111. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/s3.md +0 -0
  112. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/salesforce.md +0 -0
  113. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/sap-hana.md +0 -0
  114. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/sftp.md +0 -0
  115. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/shopify.md +0 -0
  116. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/slack.md +0 -0
  117. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/smartsheets.md +0 -0
  118. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/snowflake.md +0 -0
  119. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/solidgate.md +0 -0
  120. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/spanner.md +0 -0
  121. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/sqlite.md +0 -0
  122. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/stripe.md +0 -0
  123. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/tiktok-ads.md +0 -0
  124. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/trustpilot.md +0 -0
  125. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/zendesk.md +0 -0
  126. {ingestr-0.13.80 → ingestr-0.13.81}/docs/supported-sources/zoom.md +0 -0
  127. {ingestr-0.13.80 → ingestr-0.13.81}/docs/tutorials/load-kinesis-bigquery.md +0 -0
  128. {ingestr-0.13.80 → ingestr-0.13.81}/docs/tutorials/load-personio-duckdb.md +0 -0
  129. {ingestr-0.13.80 → ingestr-0.13.81}/docs/tutorials/load-stripe-postgres.md +0 -0
  130. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/conftest.py +0 -0
  131. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/main.py +0 -0
  132. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/.gitignore +0 -0
  133. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/adjust/__init__.py +0 -0
  134. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/adjust/adjust_helpers.py +0 -0
  135. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/airtable/__init__.py +0 -0
  136. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/applovin/__init__.py +0 -0
  137. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/applovin_max/__init__.py +0 -0
  138. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/appsflyer/__init__.py +0 -0
  139. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/appsflyer/client.py +0 -0
  140. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/appstore/__init__.py +0 -0
  141. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/appstore/client.py +0 -0
  142. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/appstore/errors.py +0 -0
  143. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/appstore/models.py +0 -0
  144. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/appstore/resources.py +0 -0
  145. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/arrow/__init__.py +0 -0
  146. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/asana_source/__init__.py +0 -0
  147. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/asana_source/helpers.py +0 -0
  148. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/asana_source/settings.py +0 -0
  149. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/attio/__init__.py +0 -0
  150. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/attio/helpers.py +0 -0
  151. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/blob.py +0 -0
  152. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/chess/__init__.py +0 -0
  153. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/chess/helpers.py +0 -0
  154. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/chess/settings.py +0 -0
  155. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/clickup/__init__.py +0 -0
  156. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/clickup/helpers.py +0 -0
  157. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/collector/spinner.py +0 -0
  158. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/destinations.py +0 -0
  159. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/dynamodb/__init__.py +0 -0
  160. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/elasticsearch/__init__.py +0 -0
  161. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/errors.py +0 -0
  162. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/facebook_ads/exceptions.py +0 -0
  163. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/facebook_ads/settings.py +0 -0
  164. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/facebook_ads/utils.py +0 -0
  165. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/factory.py +0 -0
  166. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/filesystem/__init__.py +0 -0
  167. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/filesystem/helpers.py +0 -0
  168. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/filesystem/readers.py +0 -0
  169. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/filters.py +0 -0
  170. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/frankfurter/__init__.py +0 -0
  171. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/frankfurter/helpers.py +0 -0
  172. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/freshdesk/__init__.py +0 -0
  173. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/freshdesk/freshdesk_client.py +0 -0
  174. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/freshdesk/settings.py +0 -0
  175. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/github/__init__.py +0 -0
  176. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/github/helpers.py +0 -0
  177. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/github/queries.py +0 -0
  178. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/github/settings.py +0 -0
  179. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/google_ads/__init__.py +0 -0
  180. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/google_ads/field.py +0 -0
  181. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/google_ads/metrics.py +0 -0
  182. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/google_ads/predicates.py +0 -0
  183. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/google_ads/reports.py +0 -0
  184. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/google_analytics/__init__.py +0 -0
  185. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/google_analytics/helpers.py +0 -0
  186. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/google_sheets/README.md +0 -0
  187. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/google_sheets/__init__.py +0 -0
  188. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
  189. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
  190. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
  191. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/gorgias/__init__.py +0 -0
  192. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/gorgias/helpers.py +0 -0
  193. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/http_client.py +0 -0
  194. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/hubspot/__init__.py +0 -0
  195. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/hubspot/helpers.py +0 -0
  196. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/hubspot/settings.py +0 -0
  197. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/influxdb/__init__.py +0 -0
  198. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/influxdb/client.py +0 -0
  199. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/isoc_pulse/__init__.py +0 -0
  200. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/kafka/__init__.py +0 -0
  201. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/kafka/helpers.py +0 -0
  202. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/kinesis/__init__.py +0 -0
  203. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/kinesis/helpers.py +0 -0
  204. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/klaviyo/__init__.py +0 -0
  205. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/klaviyo/client.py +0 -0
  206. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/klaviyo/helpers.py +0 -0
  207. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/linkedin_ads/__init__.py +0 -0
  208. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/linkedin_ads/dimension_time_enum.py +0 -0
  209. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/linkedin_ads/helpers.py +0 -0
  210. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/loader.py +0 -0
  211. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/mixpanel/__init__.py +0 -0
  212. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/mixpanel/client.py +0 -0
  213. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/mongodb/__init__.py +0 -0
  214. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/mongodb/helpers.py +0 -0
  215. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/notion/__init__.py +0 -0
  216. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/notion/helpers/__init__.py +0 -0
  217. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/notion/helpers/client.py +0 -0
  218. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/notion/helpers/database.py +0 -0
  219. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/notion/settings.py +0 -0
  220. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/partition.py +0 -0
  221. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/personio/__init__.py +0 -0
  222. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/personio/helpers.py +0 -0
  223. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/phantombuster/__init__.py +0 -0
  224. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/phantombuster/client.py +0 -0
  225. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/pinterest/__init__.py +0 -0
  226. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/pipedrive/__init__.py +0 -0
  227. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/pipedrive/helpers/__init__.py +0 -0
  228. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/pipedrive/helpers/custom_fields_munger.py +0 -0
  229. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/pipedrive/helpers/pages.py +0 -0
  230. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/pipedrive/settings.py +0 -0
  231. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/pipedrive/typing.py +0 -0
  232. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/quickbooks/__init__.py +0 -0
  233. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/resource.py +0 -0
  234. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/salesforce/__init__.py +0 -0
  235. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/salesforce/helpers.py +0 -0
  236. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/shopify/__init__.py +0 -0
  237. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/shopify/exceptions.py +0 -0
  238. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/shopify/helpers.py +0 -0
  239. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/shopify/settings.py +0 -0
  240. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/slack/__init__.py +0 -0
  241. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/slack/helpers.py +0 -0
  242. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/slack/settings.py +0 -0
  243. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/smartsheets/__init__.py +0 -0
  244. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/solidgate/__init__.py +0 -0
  245. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/solidgate/helpers.py +0 -0
  246. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/sql_database/__init__.py +0 -0
  247. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/sql_database/callbacks.py +0 -0
  248. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/stripe_analytics/__init__.py +0 -0
  249. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/stripe_analytics/helpers.py +0 -0
  250. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/stripe_analytics/settings.py +0 -0
  251. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/table_definition.py +0 -0
  252. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/telemetry/event.py +0 -0
  253. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/testdata/fakebqcredentials.json +0 -0
  254. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/tiktok_ads/__init__.py +0 -0
  255. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/tiktok_ads/tiktok_helpers.py +0 -0
  256. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/time.py +0 -0
  257. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/trustpilot/__init__.py +0 -0
  258. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/trustpilot/client.py +0 -0
  259. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/version.py +0 -0
  260. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/zendesk/__init__.py +0 -0
  261. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/zendesk/helpers/__init__.py +0 -0
  262. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
  263. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/zendesk/helpers/credentials.py +0 -0
  264. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
  265. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/zendesk/settings.py +0 -0
  266. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/zoom/__init__.py +0 -0
  267. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/src/zoom/helpers.py +0 -0
  268. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/testdata/.gitignore +0 -0
  269. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/testdata/create_replace.csv +0 -0
  270. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/testdata/delete_insert_expected.csv +0 -0
  271. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/testdata/delete_insert_part1.csv +0 -0
  272. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/testdata/delete_insert_part2.csv +0 -0
  273. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/testdata/merge_expected.csv +0 -0
  274. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/testdata/merge_part1.csv +0 -0
  275. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/testdata/merge_part2.csv +0 -0
  276. {ingestr-0.13.80 → ingestr-0.13.81}/ingestr/tests/unit/test_smartsheets.py +0 -0
  277. {ingestr-0.13.80 → ingestr-0.13.81}/package-lock.json +0 -0
  278. {ingestr-0.13.80 → ingestr-0.13.81}/package.json +0 -0
  279. {ingestr-0.13.80 → ingestr-0.13.81}/pyproject.toml +0 -0
  280. {ingestr-0.13.80 → ingestr-0.13.81}/requirements-dev.txt +0 -0
  281. {ingestr-0.13.80 → ingestr-0.13.81}/requirements.in +0 -0
  282. {ingestr-0.13.80 → ingestr-0.13.81}/requirements.txt +0 -0
  283. {ingestr-0.13.80 → ingestr-0.13.81}/requirements_arm64.txt +0 -0
  284. {ingestr-0.13.80 → ingestr-0.13.81}/resources/demo.gif +0 -0
  285. {ingestr-0.13.80 → ingestr-0.13.81}/resources/demo.tape +0 -0
  286. {ingestr-0.13.80 → ingestr-0.13.81}/resources/ingestr.svg +0 -0
  287. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/AMPM.yml +0 -0
  288. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Acronyms.yml +0 -0
  289. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Colons.yml +0 -0
  290. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Contractions.yml +0 -0
  291. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/DateFormat.yml +0 -0
  292. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Ellipses.yml +0 -0
  293. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/EmDash.yml +0 -0
  294. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Exclamation.yml +0 -0
  295. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/FirstPerson.yml +0 -0
  296. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Gender.yml +0 -0
  297. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/GenderBias.yml +0 -0
  298. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/HeadingPunctuation.yml +0 -0
  299. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Headings.yml +0 -0
  300. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Latin.yml +0 -0
  301. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/LyHyphens.yml +0 -0
  302. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/OptionalPlurals.yml +0 -0
  303. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Ordinal.yml +0 -0
  304. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/OxfordComma.yml +0 -0
  305. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Parens.yml +0 -0
  306. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Passive.yml +0 -0
  307. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Periods.yml +0 -0
  308. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Quotes.yml +0 -0
  309. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Ranges.yml +0 -0
  310. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Semicolons.yml +0 -0
  311. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Slang.yml +0 -0
  312. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Spacing.yml +0 -0
  313. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Spelling.yml +0 -0
  314. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Units.yml +0 -0
  315. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/We.yml +0 -0
  316. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/Will.yml +0 -0
  317. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/WordList.yml +0 -0
  318. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/meta.json +0 -0
  319. {ingestr-0.13.80 → ingestr-0.13.81}/styles/Google/vocab.txt +0 -0
  320. {ingestr-0.13.80 → ingestr-0.13.81}/styles/bruin/Ingestr.yml +0 -0
  321. {ingestr-0.13.80 → ingestr-0.13.81}/styles/config/vocabularies/bruin/accept.txt +0 -0
  322. {ingestr-0.13.80 → ingestr-0.13.81}/test.env.template +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ingestr
3
- Version: 0.13.80
3
+ Version: 0.13.81
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
@@ -160,13 +160,19 @@ The `facebook_insights` table supports advanced configuration for breakdowns and
160
160
  1. **Default usage**: `facebook_insights`
161
161
  - Uses default breakdown and default fields
162
162
 
163
- 2. **Custom breakdown**: `facebook_insights:breakdown_type`
164
- - Uses specified breakdown with default fields
163
+ 2. **Predefined breakdown**: `facebook_insights:breakdown_type`
164
+ - Uses specified predefined breakdown with default fields
165
165
 
166
- 3. **Custom breakdown + metrics**: `facebook_insights:breakdown_type:metric1,metric2,metric3`
167
- - Uses specified breakdown with custom metrics
166
+ 3. **Predefined breakdown + custom metrics**: `facebook_insights:breakdown_type:metric1,metric2,metric3`
167
+ - Uses specified predefined breakdown with custom metrics
168
168
 
169
- #### Available Breakdown Types
169
+ 4. **Custom dimensions + metrics**: `facebook_insights:dimension1,dimension2:metric1,metric2,metric3`
170
+ - Uses custom dimensions with custom metrics
171
+
172
+ 5. **Level + dimensions + metrics**: `facebook_insights:level,dimension1,dimension2:metric1,metric2,metric3`
173
+ - Uses specified level with custom dimensions and metrics
174
+
175
+ #### Available Predefined Breakdown Types
170
176
 
171
177
  - `ads_insights` (default)
172
178
  - `ads_insights_age_and_gender`
@@ -176,6 +182,30 @@ The `facebook_insights` table supports advanced configuration for breakdowns and
176
182
  - `ads_insights_dma`
177
183
  - `ads_insights_hourly_advertiser`
178
184
 
185
+ #### Available Levels
186
+
187
+ When using custom dimensions, you can specify one of these levels:
188
+ - `account` - Account level insights
189
+ - `campaign` - Campaign level insights
190
+ - `adset` - Ad set level insights
191
+ - `ad` - Ad level insights
192
+
193
+ Note: If multiple levels are specified in the dimensions list, the last valid level will be used and removed from the dimensions list.
194
+
195
+ #### Common Dimensions
196
+
197
+ You can use any valid Facebook Ads dimension in your custom configurations. Some commonly used dimensions include:
198
+ - `age` - Age ranges
199
+ - `gender` - Gender breakdown
200
+ - `country` - Country breakdown
201
+ - `region` - Region breakdown
202
+ - `platform_position` - Platform position
203
+ - `publisher_platform` - Publisher platform
204
+ - `impression_device` - Device type
205
+ - `placement` - Ad placement
206
+
207
+ Note: Not all dimension combinations are valid according to Facebook's API. Refer to [Facebook's Marketing API](https://developers.facebook.com/docs/marketing-api/insights/breakdowns/) documentation for valid dimension combinations.
208
+
179
209
  #### Examples
180
210
 
181
211
  ```sh
@@ -199,4 +229,32 @@ ingestr ingest \
199
229
  --source-table 'facebook_insights:ads_insights_country:impressions,clicks,spend,reach,cpm,ctr' \
200
230
  --dest-uri 'duckdb:///facebook.duckdb' \
201
231
  --dest-table 'dest.insights_by_country'
232
+
233
+ # Custom dimensions (age and gender) with custom metrics
234
+ ingestr ingest \
235
+ --source-uri 'facebookads://?access_token=easdyh&account_id=1234' \
236
+ --source-table 'facebook_insights:age,gender:impressions,clicks,spend' \
237
+ --dest-uri 'duckdb:///facebook.duckdb' \
238
+ --dest-table 'dest.insights_custom_dimensions'
239
+
240
+ # Campaign level with custom dimensions and metrics
241
+ ingestr ingest \
242
+ --source-uri 'facebookads://?access_token=easdyh&account_id=1234' \
243
+ --source-table 'facebook_insights:campaign,age,gender:impressions,clicks,spend,reach' \
244
+ --dest-uri 'duckdb:///facebook.duckdb' \
245
+ --dest-table 'dest.campaign_insights_demographics'
246
+
247
+ # Ad level with geographic dimensions
248
+ ingestr ingest \
249
+ --source-uri 'facebookads://?access_token=easdyh&account_id=1234' \
250
+ --source-table 'facebook_insights:ad,country,region:clicks,impressions,spend' \
251
+ --dest-uri 'duckdb:///facebook.duckdb' \
252
+ --dest-table 'dest.ad_insights_geographic'
253
+
254
+ # Account level insights only (no additional dimensions)
255
+ ingestr ingest \
256
+ --source-uri 'facebookads://?access_token=easdyh&account_id=1234' \
257
+ --source-table 'facebook_insights:account:impressions,clicks,spend,reach' \
258
+ --dest-uri 'duckdb:///facebook.duckdb' \
259
+ --dest-table 'dest.account_level_insights'
202
260
  ```
@@ -0,0 +1 @@
1
+ version = "v0.13.81"
@@ -22,12 +22,8 @@ from .settings import (
22
22
  DEFAULT_ADCREATIVE_FIELDS,
23
23
  DEFAULT_ADSET_FIELDS,
24
24
  DEFAULT_CAMPAIGN_FIELDS,
25
- DEFAULT_INSIGHT_FIELDS,
26
25
  DEFAULT_LEAD_FIELDS,
27
26
  INSIGHT_FIELDS_TYPES,
28
- INSIGHTS_BREAKDOWNS_OPTIONS,
29
- INVALID_INSIGHTS_FIELDS,
30
- TInsightsBreakdownOptions,
31
27
  TInsightsLevels,
32
28
  )
33
29
 
@@ -105,10 +101,9 @@ def facebook_insights_source(
105
101
  account_id: str = dlt.config.value,
106
102
  access_token: str = dlt.secrets.value,
107
103
  initial_load_past_days: int = 1,
108
- fields: Sequence[str] = DEFAULT_INSIGHT_FIELDS,
109
- attribution_window_days_lag: int = 7,
104
+ dimensions: Sequence[str] = None,
105
+ fields: Sequence[str] = None,
110
106
  time_increment_days: int = 1,
111
- breakdowns: TInsightsBreakdownOptions = "ads_insights",
112
107
  action_breakdowns: Sequence[str] = ALL_ACTION_BREAKDOWNS,
113
108
  level: TInsightsLevels = "ad",
114
109
  action_attribution_windows: Sequence[str] = ALL_ACTION_ATTRIBUTION_WINDOWS,
@@ -155,6 +150,11 @@ def facebook_insights_source(
155
150
  if start_date is None:
156
151
  start_date = pendulum.today().subtract(days=initial_load_past_days)
157
152
 
153
+ if dimensions is None:
154
+ dimensions = []
155
+ if fields is None:
156
+ fields = []
157
+
158
158
  columns = {}
159
159
  for field in fields:
160
160
  if field in INSIGHT_FIELDS_TYPES:
@@ -187,15 +187,9 @@ def facebook_insights_source(
187
187
  query = {
188
188
  "level": level,
189
189
  "action_breakdowns": list(action_breakdowns),
190
- "breakdowns": list(
191
- INSIGHTS_BREAKDOWNS_OPTIONS[breakdowns]["breakdowns"]
192
- ),
190
+ "breakdowns": dimensions,
193
191
  "limit": batch_size,
194
- "fields": list(
195
- set(fields)
196
- .union(INSIGHTS_BREAKDOWNS_OPTIONS[breakdowns]["fields"])
197
- .difference(INVALID_INSIGHTS_FIELDS)
198
- ),
192
+ "fields": fields,
199
193
  "time_increment": time_increment_days,
200
194
  "action_attribution_windows": list(action_attribution_windows),
201
195
  "time_ranges": [
@@ -229,3 +229,49 @@ def notify_on_token_expiration(access_token_expires_at: int = None) -> None:
229
229
  logger.error(
230
230
  f"Access Token expires in {humanize.precisedelta(pendulum.now() - expires_at)}. Replace the token now!"
231
231
  )
232
+
233
+
234
+ def parse_insights_table_to_source_kwargs(table: str) -> DictStrAny:
235
+ import typing
236
+
237
+ from ingestr.src.facebook_ads.settings import (
238
+ INSIGHTS_BREAKDOWNS_OPTIONS,
239
+ TInsightsBreakdownOptions,
240
+ TInsightsLevels,
241
+ )
242
+
243
+ parts = table.split(":")
244
+
245
+ source_kwargs = {}
246
+
247
+ breakdown_type = parts[1]
248
+
249
+ valid_breakdowns = list(typing.get_args(TInsightsBreakdownOptions))
250
+ if breakdown_type in valid_breakdowns:
251
+ dimensions = INSIGHTS_BREAKDOWNS_OPTIONS[breakdown_type]["breakdowns"]
252
+ fields = INSIGHTS_BREAKDOWNS_OPTIONS[breakdown_type]["fields"]
253
+ source_kwargs["dimensions"] = dimensions
254
+ source_kwargs["fields"] = fields
255
+ else:
256
+ dimensions = breakdown_type.split(",")
257
+ valid_levels = list(typing.get_args(TInsightsLevels))
258
+ level = None
259
+ for valid_level in reversed(valid_levels):
260
+ if valid_level in dimensions:
261
+ level = valid_level
262
+ dimensions.remove(valid_level)
263
+ break
264
+
265
+ source_kwargs["level"] = level
266
+ source_kwargs["dimensions"] = dimensions
267
+
268
+ # If custom metrics are provided, parse them
269
+ if len(parts) == 3:
270
+ fields = [f.strip() for f in parts[2].split(",") if f.strip()]
271
+ if not fields:
272
+ raise ValueError(
273
+ "Custom metrics must be provided after the second colon in format: facebook_insights:breakdown_type:metric1,metric2..."
274
+ )
275
+ source_kwargs["fields"] = fields
276
+
277
+ return source_kwargs
@@ -17,9 +17,10 @@ def _get_date_range(updated_at, start_date):
17
17
  current_end_date = pendulum.parse(updated_at.end_value)
18
18
  else:
19
19
  current_end_date = pendulum.now(tz="UTC")
20
-
20
+
21
21
  return current_start_date, current_end_date
22
22
 
23
+
23
24
  ISSUES_QUERY = """
24
25
  query Issues($cursor: String) {
25
26
  issues(first: 50, after: $cursor) {
@@ -119,6 +120,7 @@ query WorkflowStates($cursor: String) {
119
120
  }
120
121
  """
121
122
 
123
+
122
124
  @dlt.source(name="linear", max_table_nesting=0)
123
125
  def linear_source(
124
126
  api_key: str,
@@ -211,5 +213,5 @@ def linear_source(
211
213
  if pendulum.parse(item["updatedAt"]) >= current_start_date:
212
214
  if pendulum.parse(item["updatedAt"]) <= current_end_date:
213
215
  yield normalize_dictionaries(item)
214
- return [issues, projects, teams, users, workflow_states]
215
216
 
217
+ return [issues, projects, teams, users, workflow_states]
@@ -32,8 +32,6 @@ def _paginate(api_key: str, query: str, root: str) -> Iterator[Dict[str, Any]]:
32
32
  cursor = data["pageInfo"]["endCursor"]
33
33
 
34
34
 
35
-
36
-
37
35
  def normalize_dictionaries(item: Dict[str, Any]) -> Dict[str, Any]:
38
36
  """
39
37
  Automatically normalize dictionary fields by detecting their structure:
@@ -41,15 +39,15 @@ def normalize_dictionaries(item: Dict[str, Any]) -> Dict[str, Any]:
41
39
  - Convert objects with 'nodes' field to arrays
42
40
  """
43
41
  normalized_item = item.copy()
44
-
42
+
45
43
  for key, value in list(normalized_item.items()):
46
44
  if isinstance(value, dict):
47
45
  # If the dict has an 'id' field, replace with {key}_id
48
- if 'id' in value:
49
- normalized_item[f"{key}_id"] = value['id']
46
+ if "id" in value:
47
+ normalized_item[f"{key}_id"] = value["id"]
50
48
  del normalized_item[key]
51
49
  # If the dict has 'nodes' field, extract the nodes array
52
- elif 'nodes' in value:
53
- normalized_item[key] = value['nodes']
54
-
50
+ elif "nodes" in value:
51
+ normalized_item[key] = value["nodes"]
52
+
55
53
  return normalized_item
@@ -1056,33 +1056,16 @@ class FacebookAdsSource:
1056
1056
  # Validate breakdown type against available options from settings
1057
1057
  import typing
1058
1058
 
1059
- from ingestr.src.facebook_ads.settings import TInsightsBreakdownOptions
1060
-
1061
- # Get valid breakdown options from the type definition
1062
- valid_breakdowns = list(typing.get_args(TInsightsBreakdownOptions))
1063
-
1064
- if breakdown_type not in valid_breakdowns:
1065
- raise ValueError(
1066
- f"Invalid breakdown type '{breakdown_type}'. Valid options: {', '.join(valid_breakdowns)}"
1067
- )
1059
+ from ingestr.src.facebook_ads.helpers import parse_insights_table_to_source_kwargs
1068
1060
 
1069
1061
  source_kwargs = {
1070
1062
  "access_token": access_token[0],
1071
1063
  "account_id": account_id[0],
1072
1064
  "start_date": kwargs.get("interval_start"),
1073
1065
  "end_date": kwargs.get("interval_end"),
1074
- "breakdowns": breakdown_type,
1075
1066
  }
1076
1067
 
1077
- # If custom metrics are provided, parse them
1078
- if len(parts) == 3:
1079
- fields = [f.strip() for f in parts[2].split(",") if f.strip()]
1080
- if not fields:
1081
- raise ValueError(
1082
- "Custom metrics must be provided after the second colon in format: facebook_insights:breakdown_type:metric1,metric2..."
1083
- )
1084
- source_kwargs["fields"] = fields
1085
-
1068
+ source_kwargs.update(parse_insights_table_to_source_kwargs(table))
1086
1069
  return facebook_insights_source(**source_kwargs).with_resources(
1087
1070
  "facebook_insights"
1088
1071
  )
@@ -1 +0,0 @@
1
- version = "v0.13.80"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes