ingestr 0.13.53__tar.gz → 0.13.55__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.
- {ingestr-0.13.53 → ingestr-0.13.55}/PKG-INFO +8 -1
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/.vitepress/config.mjs +3 -1
- ingestr-0.13.55/docs/media/mixpanel_ingestion.png +0 -0
- ingestr-0.13.55/docs/media/quickbook_ingestion.png +0 -0
- ingestr-0.13.55/docs/supported-sources/facebook-ads.md +202 -0
- ingestr-0.13.55/docs/supported-sources/mixpanel.md +46 -0
- ingestr-0.13.55/docs/supported-sources/quickbooks.md +49 -0
- ingestr-0.13.55/ingestr/src/buildinfo.py +1 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/destinations.py +1 -4
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/facebook_ads/__init__.py +18 -8
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/facebook_ads/helpers.py +2 -4
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/facebook_ads/settings.py +2 -0
- ingestr-0.13.55/ingestr/src/facebook_ads/utils.py +39 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/factory.py +4 -0
- ingestr-0.13.55/ingestr/src/mixpanel/__init__.py +62 -0
- ingestr-0.13.55/ingestr/src/mixpanel/client.py +99 -0
- ingestr-0.13.55/ingestr/src/quickbooks/__init__.py +117 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/sources.py +176 -4
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/stripe_analytics/__init__.py +4 -2
- {ingestr-0.13.53 → ingestr-0.13.55}/package-lock.json +3 -3
- {ingestr-0.13.53 → ingestr-0.13.55}/requirements.in +1 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/requirements.txt +30 -2
- {ingestr-0.13.53 → ingestr-0.13.55}/requirements_arm64.txt +33 -5
- ingestr-0.13.53/docs/supported-sources/facebook-ads.md +0 -51
- ingestr-0.13.53/ingestr/src/buildinfo.py +0 -1
- {ingestr-0.13.53 → ingestr-0.13.55}/.dockerignore +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/.githooks/pre-commit-hook.sh +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/.github/workflows/deploy-docs.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/.github/workflows/release.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/.github/workflows/secrets-scan.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/.github/workflows/tests.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/.gitignore +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/.gitleaksignore +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/.python-version +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/.vale.ini +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/Dockerfile +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/LICENSE.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/Makefile +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/README.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/.vitepress/theme/custom.css +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/.vitepress/theme/index.js +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/commands/example-uris.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/commands/ingest.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/getting-started/core-concepts.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/getting-started/incremental-loading.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/getting-started/quickstart.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/getting-started/telemetry.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/index.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/applovin_max.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/athena.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/clickhouse_img.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/cratedb-source.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/freshdesk_ingestion.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/gcp_spanner_ingestion.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/github.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/google_analytics_realtime_report.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/googleanalytics.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/ingestion_elasticsearch_img.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/kinesis.bigquery.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/linkedin_ads.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/personio.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/personio_duckdb.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/phantombuster.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/pipedrive.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/sftp.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/stripe_postgres.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/media/tiktok.png +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/adjust.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/airtable.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/applovin.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/applovin_max.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/appsflyer.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/appstore.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/asana.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/athena.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/attio.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/bigquery.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/chess.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/clickhouse.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/cratedb.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/csv.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/custom_queries.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/databricks.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/db2.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/duckdb.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/dynamodb.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/elasticsearch.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/frankfurter.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/freshdesk.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/gcs.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/github.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/google-ads.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/google_analytics.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/gorgias.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/gsheets.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/hubspot.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/kafka.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/kinesis.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/klaviyo.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/linkedin_ads.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/mongodb.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/mssql.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/mysql.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/notion.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/oracle.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/personio.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/phantombuster.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/pipedrive.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/postgres.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/redshift.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/s3.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/salesforce.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/sap-hana.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/sftp.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/shopify.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/slack.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/smartsheets.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/snowflake.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/solidgate.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/spanner.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/sqlite.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/stripe.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/tiktok-ads.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/supported-sources/zendesk.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/tutorials/load-kinesis-bigquery.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/tutorials/load-personio-duckdb.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/docs/tutorials/load-stripe-postgres.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/conftest.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/main.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/.gitignore +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/adjust/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/adjust/adjust_helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/airtable/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/applovin/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/applovin_max/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/appsflyer/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/appsflyer/client.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/appstore/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/appstore/client.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/appstore/errors.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/appstore/models.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/appstore/resources.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/arrow/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/asana_source/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/asana_source/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/asana_source/settings.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/attio/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/attio/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/blob.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/chess/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/chess/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/chess/settings.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/collector/spinner.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/dynamodb/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/elasticsearch/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/errors.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/facebook_ads/exceptions.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/filesystem/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/filesystem/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/filesystem/readers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/filters.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/frankfurter/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/frankfurter/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/freshdesk/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/freshdesk/freshdesk_client.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/freshdesk/settings.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/github/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/github/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/github/queries.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/github/settings.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/google_ads/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/google_ads/field.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/google_ads/metrics.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/google_ads/predicates.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/google_ads/reports.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/google_analytics/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/google_analytics/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/google_sheets/README.md +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/google_sheets/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/gorgias/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/gorgias/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/http_client.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/hubspot/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/hubspot/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/hubspot/settings.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/kafka/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/kafka/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/kinesis/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/kinesis/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/klaviyo/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/klaviyo/client.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/klaviyo/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/linkedin_ads/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/linkedin_ads/dimension_time_enum.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/linkedin_ads/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/loader.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/mongodb/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/mongodb/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/notion/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/notion/helpers/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/notion/helpers/client.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/notion/helpers/database.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/notion/settings.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/partition.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/personio/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/personio/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/phantombuster/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/phantombuster/client.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/pipedrive/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/pipedrive/helpers/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/pipedrive/helpers/custom_fields_munger.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/pipedrive/helpers/pages.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/pipedrive/settings.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/pipedrive/typing.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/resource.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/salesforce/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/salesforce/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/shopify/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/shopify/exceptions.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/shopify/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/shopify/settings.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/slack/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/slack/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/slack/settings.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/smartsheets/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/solidgate/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/solidgate/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/sql_database/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/sql_database/callbacks.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/stripe_analytics/helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/stripe_analytics/settings.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/table_definition.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/telemetry/event.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/testdata/fakebqcredentials.json +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/tiktok_ads/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/tiktok_ads/tiktok_helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/time.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/version.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/zendesk/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/zendesk/helpers/__init__.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/zendesk/helpers/credentials.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/src/zendesk/settings.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/testdata/.gitignore +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/testdata/create_replace.csv +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/testdata/delete_insert_expected.csv +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/testdata/delete_insert_part1.csv +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/testdata/delete_insert_part2.csv +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/testdata/merge_expected.csv +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/testdata/merge_part1.csv +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/testdata/merge_part2.csv +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/ingestr/tests/unit/test_smartsheets.py +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/package.json +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/pyproject.toml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/requirements-dev.txt +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/resources/demo.gif +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/resources/demo.tape +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/resources/ingestr.svg +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/AMPM.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Acronyms.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Colons.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Contractions.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/DateFormat.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Ellipses.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/EmDash.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Exclamation.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/FirstPerson.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Gender.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/GenderBias.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/HeadingPunctuation.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Headings.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Latin.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/LyHyphens.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/OptionalPlurals.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Ordinal.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/OxfordComma.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Parens.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Passive.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Periods.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Quotes.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Ranges.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Semicolons.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Slang.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Spacing.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Spelling.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Units.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/We.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/Will.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/WordList.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/meta.json +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/Google/vocab.txt +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/bruin/Ingestr.yml +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/styles/config/vocabularies/bruin/accept.txt +0 -0
- {ingestr-0.13.53 → ingestr-0.13.55}/test.env.template +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ingestr
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.55
|
|
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
|
|
@@ -52,14 +52,17 @@ Requires-Dist: dlt==1.10.0
|
|
|
52
52
|
Requires-Dist: dnspython==2.7.0
|
|
53
53
|
Requires-Dist: duckdb-engine==0.17.0
|
|
54
54
|
Requires-Dist: duckdb==1.2.1
|
|
55
|
+
Requires-Dist: ecdsa==0.19.1
|
|
55
56
|
Requires-Dist: elastic-transport==8.17.1
|
|
56
57
|
Requires-Dist: elasticsearch==8.10.1
|
|
58
|
+
Requires-Dist: enum-compat==0.0.3
|
|
57
59
|
Requires-Dist: et-xmlfile==2.0.0
|
|
58
60
|
Requires-Dist: facebook-business==20.0.0
|
|
59
61
|
Requires-Dist: filelock==3.17.0
|
|
60
62
|
Requires-Dist: flatten-json==0.1.14
|
|
61
63
|
Requires-Dist: frozenlist==1.5.0
|
|
62
64
|
Requires-Dist: fsspec==2025.3.2
|
|
65
|
+
Requires-Dist: future==1.0.0
|
|
63
66
|
Requires-Dist: gcsfs==2025.3.2
|
|
64
67
|
Requires-Dist: geojson==3.2.0
|
|
65
68
|
Requires-Dist: gitdb==4.0.12
|
|
@@ -93,6 +96,7 @@ Requires-Dist: ibm-db-sa==0.4.1
|
|
|
93
96
|
Requires-Dist: ibm-db==3.2.6
|
|
94
97
|
Requires-Dist: idna==3.10
|
|
95
98
|
Requires-Dist: inflection==0.5.1
|
|
99
|
+
Requires-Dist: intuit-oauth==1.2.4
|
|
96
100
|
Requires-Dist: isodate==0.7.2
|
|
97
101
|
Requires-Dist: jmespath==1.0.1
|
|
98
102
|
Requires-Dist: jsonpath-ng==1.7.0
|
|
@@ -147,8 +151,11 @@ Requires-Dist: pyparsing==3.2.1
|
|
|
147
151
|
Requires-Dist: pyrate-limiter==3.7.0
|
|
148
152
|
Requires-Dist: python-dateutil==2.9.0.post0
|
|
149
153
|
Requires-Dist: python-dotenv==1.0.1
|
|
154
|
+
Requires-Dist: python-jose==3.5.0
|
|
155
|
+
Requires-Dist: python-quickbooks==0.9.2
|
|
150
156
|
Requires-Dist: pytz==2025.1
|
|
151
157
|
Requires-Dist: pyyaml==6.0.2
|
|
158
|
+
Requires-Dist: rauth==0.7.3
|
|
152
159
|
Requires-Dist: redshift-connector==2.1.5
|
|
153
160
|
Requires-Dist: requests-file==2.1.0
|
|
154
161
|
Requires-Dist: requests-oauthlib==1.3.1
|
|
@@ -132,11 +132,13 @@ export default defineConfig({
|
|
|
132
132
|
{ text: "HubSpot", link: "/supported-sources/hubspot.md" },
|
|
133
133
|
{ text: "Klaviyo", link: "/supported-sources/klaviyo.md" },
|
|
134
134
|
{ text: "LinkedIn Ads", link: "/supported-sources/linkedin_ads.md" },
|
|
135
|
+
{ text: "Mixpanel", link: "/supported-sources/mixpanel.md" },
|
|
135
136
|
{ text: "Notion", link: "/supported-sources/notion.md" },
|
|
136
137
|
{ text: "Personio", link: "/supported-sources/personio.md" },
|
|
137
138
|
{ text: "PhantomBuster", link: "/supported-sources/phantombuster.md" },
|
|
138
139
|
{ text: "Pipedrive", link: "/supported-sources/pipedrive.md" },
|
|
139
|
-
{ text: "
|
|
140
|
+
{ text: "QuickBooks", link: "/supported-sources/quickbooks.md" },
|
|
141
|
+
{ text: "S3", link: "/supported-sources/s3.md" },
|
|
140
142
|
{ text: "Salesforce", link: "/supported-sources/salesforce.md" },
|
|
141
143
|
{ text: "SFTP", link: "/supported-sources/sftp.md"},
|
|
142
144
|
{ text: "Shopify", link: "/supported-sources/shopify.md" },
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Mixpanel
|
|
2
|
+
|
|
3
|
+
[Mixpanel](https://mixpanel.com/) is an analytics service for tracking user interactions in web and mobile applications.
|
|
4
|
+
|
|
5
|
+
ingestr supports Mixpanel as a source.
|
|
6
|
+
|
|
7
|
+
## URI format
|
|
8
|
+
|
|
9
|
+
```plaintext
|
|
10
|
+
mixpanel://?username=<service_account_username>&password=<service_account_secret>&project_id=<project_id>&server=<server>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
URI parameters:
|
|
14
|
+
|
|
15
|
+
- `username`: Mixpanel service account username.
|
|
16
|
+
- `password`: Mixpanel service account secret. This is the secret associated with the service account.
|
|
17
|
+
- `project_id`: The numeric project ID.
|
|
18
|
+
- `server`: (Optional) The server region to use. Can be "us", "eu", or "in". Defaults to "eu".
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
To grab mixpanel credentials, please follow the guide [here](https://developer.mixpanel.com/reference/service-accounts).
|
|
22
|
+
|
|
23
|
+
## Example
|
|
24
|
+
|
|
25
|
+
Copy events from Mixpanel into a DuckDB database:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
ingestr ingest \
|
|
29
|
+
--source-uri 'mixpanel://?username=my-service-account&password=my-secret&project_id=12345' \
|
|
30
|
+
--source-table 'events' \
|
|
31
|
+
--dest-uri duckdb:///mixpanel.duckdb \
|
|
32
|
+
--dest-table 'mixpanel.events'
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
<img alt="mixpanel" src="../media/mixpanel_ingestion.png"/>
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## Tables
|
|
40
|
+
|
|
41
|
+
Mixpanel source allows ingesting the following tables:
|
|
42
|
+
|
|
43
|
+
- `events`: Raw event data returned from the export API.
|
|
44
|
+
- `profiles`: User profiles from the Engage API.
|
|
45
|
+
|
|
46
|
+
Use these as `--source-table` values in the `ingestr ingest` command.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# QuickBooks
|
|
2
|
+
|
|
3
|
+
[QuickBooks](https://quickbooks.intuit.com/) is an accounting software package developed and marketed by Intuit.
|
|
4
|
+
|
|
5
|
+
ingestr supports QuickBooks as a source.
|
|
6
|
+
|
|
7
|
+
## URI format
|
|
8
|
+
|
|
9
|
+
```plaintext
|
|
10
|
+
quickbooks://?company_id=<company_id>client_id=<client_id>&client_secret=<client_secret>&refresh_token=<refresh_token>&access_token=<access_token>&environment=<environment>&minor_version=<minor_version>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
URI parameters:
|
|
14
|
+
- `company_id`: The QuickBooks company (realm) id.
|
|
15
|
+
- `client_id`: OAuth client id from your Intuit application.
|
|
16
|
+
- `client_secret`: OAuth client secret.
|
|
17
|
+
- `refresh_token`: OAuth refresh token used to obtain access tokens.
|
|
18
|
+
- `environment`: Optional environment name, either `production` or `sandbox`. Defaults to `production`.
|
|
19
|
+
- `minor_version`: Optional API minor version.
|
|
20
|
+
|
|
21
|
+
## Setting up a QuickBooks integration
|
|
22
|
+
|
|
23
|
+
Follow Intuit's [OAuth setup guide](https://developer.intuit.com/app/developer/qbo/docs/develop/authentication-and-authorization) to create an app and generate your credentials.
|
|
24
|
+
|
|
25
|
+
Once you have the credentials, you can ingest data. For example, to copy customers data into DuckDB:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
ingestr ingest \
|
|
29
|
+
--source-uri 'quickbooks://?company_id=1234567890&client_id=cid&client_secret=csecret&refresh_token=rtoken' \
|
|
30
|
+
--source-table 'customers' \
|
|
31
|
+
--dest-uri duckdb:///customers.duckdb \
|
|
32
|
+
--dest-table 'dest.details'
|
|
33
|
+
```
|
|
34
|
+
This command will retrieve customers data and save it to the `dest.details` table in the DuckDB database.
|
|
35
|
+
|
|
36
|
+
<img alt="quickbooks" src="../media/quickbook_ingestion.png"/>
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
## Tables
|
|
40
|
+
QuickBooks source allows ingesting the following tables:
|
|
41
|
+
|
|
42
|
+
- `customers`: Retrives list of customers.
|
|
43
|
+
- `invoices`: Retrives sales invoices.
|
|
44
|
+
- `accounts`: Retrives details of accounts.
|
|
45
|
+
- `vendors`: Retrives vendor records.
|
|
46
|
+
- `payments`: Retrives payments recorded.
|
|
47
|
+
|
|
48
|
+
Use these as the `--source-table` parameter in the `ingestr ingest` command.
|
|
49
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "v0.13.55"
|
|
@@ -476,7 +476,7 @@ class SqliteDestination(GenericSqlDestination):
|
|
|
476
476
|
|
|
477
477
|
def dlt_run_params(self, uri: str, table: str, **kwargs):
|
|
478
478
|
return {
|
|
479
|
-
#https://dlthub.com/docs/dlt-ecosystem/destinations/sqlalchemy#dataset-files
|
|
479
|
+
# https://dlthub.com/docs/dlt-ecosystem/destinations/sqlalchemy#dataset-files
|
|
480
480
|
"dataset_name": "main",
|
|
481
481
|
"table_name": table,
|
|
482
482
|
}
|
|
@@ -495,6 +495,3 @@ class MySqlDestination(GenericSqlDestination):
|
|
|
495
495
|
"dataset_name": database,
|
|
496
496
|
"table_name": table,
|
|
497
497
|
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
@@ -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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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=
|
|
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=
|
|
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
|
|
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(
|
|
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
|
-
)
|
|
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 =
|
|
139
|
+
sleep_time = 3
|
|
142
140
|
while status != "Job Completed":
|
|
143
141
|
duration = time.time() - time_start
|
|
144
142
|
job = job.api_get()
|
|
@@ -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"]
|
|
@@ -47,11 +47,13 @@ from ingestr.src.sources import (
|
|
|
47
47
|
KlaviyoSource,
|
|
48
48
|
LinkedInAdsSource,
|
|
49
49
|
LocalCsvSource,
|
|
50
|
+
MixpanelSource,
|
|
50
51
|
MongoDbSource,
|
|
51
52
|
NotionSource,
|
|
52
53
|
PersonioSource,
|
|
53
54
|
PhantombusterSource,
|
|
54
55
|
PipedriveSource,
|
|
56
|
+
QuickBooksSource,
|
|
55
57
|
S3Source,
|
|
56
58
|
SalesforceSource,
|
|
57
59
|
SFTPSource,
|
|
@@ -140,6 +142,7 @@ class SourceDestinationFactory:
|
|
|
140
142
|
"hubspot": HubspotSource,
|
|
141
143
|
"airtable": AirtableSource,
|
|
142
144
|
"klaviyo": KlaviyoSource,
|
|
145
|
+
"mixpanel": MixpanelSource,
|
|
143
146
|
"appsflyer": AppsflyerSource,
|
|
144
147
|
"kafka": KafkaSource,
|
|
145
148
|
"adjust": AdjustSource,
|
|
@@ -166,6 +169,7 @@ class SourceDestinationFactory:
|
|
|
166
169
|
"elasticsearch": ElasticsearchSource,
|
|
167
170
|
"attio": AttioSource,
|
|
168
171
|
"solidgate": SolidgateSource,
|
|
172
|
+
"quickbooks": QuickBooksSource,
|
|
169
173
|
"smartsheet": SmartsheetSource,
|
|
170
174
|
"sftp": SFTPSource,
|
|
171
175
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from typing import Iterable
|
|
2
|
+
|
|
3
|
+
import dlt
|
|
4
|
+
import pendulum
|
|
5
|
+
from dlt.common.typing import TDataItem
|
|
6
|
+
from dlt.sources import DltResource
|
|
7
|
+
|
|
8
|
+
from .client import MixpanelClient
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dlt.source(max_table_nesting=0)
|
|
12
|
+
def mixpanel_source(
|
|
13
|
+
username: str,
|
|
14
|
+
password: str,
|
|
15
|
+
project_id: str,
|
|
16
|
+
server: str,
|
|
17
|
+
start_date: pendulum.DateTime,
|
|
18
|
+
end_date: pendulum.DateTime | None = None,
|
|
19
|
+
) -> Iterable[DltResource]:
|
|
20
|
+
client = MixpanelClient(username, password, project_id, server)
|
|
21
|
+
|
|
22
|
+
@dlt.resource(write_disposition="merge", name="events", primary_key="distinct_id")
|
|
23
|
+
def events(
|
|
24
|
+
date=dlt.sources.incremental(
|
|
25
|
+
"time",
|
|
26
|
+
initial_value=start_date.int_timestamp,
|
|
27
|
+
end_value=end_date.int_timestamp if end_date else None,
|
|
28
|
+
range_end="closed",
|
|
29
|
+
range_start="closed",
|
|
30
|
+
),
|
|
31
|
+
) -> Iterable[TDataItem]:
|
|
32
|
+
if date.end_value is None:
|
|
33
|
+
end_dt = pendulum.now(tz="UTC")
|
|
34
|
+
else:
|
|
35
|
+
end_dt = pendulum.from_timestamp(date.end_value)
|
|
36
|
+
|
|
37
|
+
start_dt = pendulum.from_timestamp(date.last_value)
|
|
38
|
+
|
|
39
|
+
yield from client.fetch_events(
|
|
40
|
+
start_dt,
|
|
41
|
+
end_dt,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
@dlt.resource(write_disposition="merge", primary_key="distinct_id", name="profiles")
|
|
45
|
+
def profiles(
|
|
46
|
+
last_seen=dlt.sources.incremental(
|
|
47
|
+
"last_seen",
|
|
48
|
+
initial_value=start_date,
|
|
49
|
+
end_value=end_date,
|
|
50
|
+
range_end="closed",
|
|
51
|
+
range_start="closed",
|
|
52
|
+
),
|
|
53
|
+
) -> Iterable[TDataItem]:
|
|
54
|
+
if last_seen.end_value is None:
|
|
55
|
+
end_dt = pendulum.now(tz="UTC")
|
|
56
|
+
else:
|
|
57
|
+
end_dt = last_seen.end_value
|
|
58
|
+
|
|
59
|
+
start_dt = last_seen.last_value
|
|
60
|
+
yield from client.fetch_profiles(start_dt, end_dt)
|
|
61
|
+
|
|
62
|
+
return events, profiles
|