ingestr 0.13.38__tar.gz → 0.13.39__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 (270) hide show
  1. {ingestr-0.13.38 → ingestr-0.13.39}/PKG-INFO +1 -1
  2. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/main.py +2 -3
  3. ingestr-0.13.39/ingestr/src/buildinfo.py +1 -0
  4. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/destinations.py +70 -0
  5. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/factory.py +4 -2
  6. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/google_analytics/helpers.py +12 -9
  7. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/phantombuster/__init__.py +9 -4
  8. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/phantombuster/client.py +29 -12
  9. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/sources.py +39 -20
  10. ingestr-0.13.38/ingestr/src/buildinfo.py +0 -1
  11. {ingestr-0.13.38 → ingestr-0.13.39}/.dockerignore +0 -0
  12. {ingestr-0.13.38 → ingestr-0.13.39}/.githooks/pre-commit-hook.sh +0 -0
  13. {ingestr-0.13.38 → ingestr-0.13.39}/.github/workflows/deploy-docs.yml +0 -0
  14. {ingestr-0.13.38 → ingestr-0.13.39}/.github/workflows/release.yml +0 -0
  15. {ingestr-0.13.38 → ingestr-0.13.39}/.github/workflows/secrets-scan.yml +0 -0
  16. {ingestr-0.13.38 → ingestr-0.13.39}/.github/workflows/tests.yml +0 -0
  17. {ingestr-0.13.38 → ingestr-0.13.39}/.gitignore +0 -0
  18. {ingestr-0.13.38 → ingestr-0.13.39}/.gitleaksignore +0 -0
  19. {ingestr-0.13.38 → ingestr-0.13.39}/.python-version +0 -0
  20. {ingestr-0.13.38 → ingestr-0.13.39}/.vale.ini +0 -0
  21. {ingestr-0.13.38 → ingestr-0.13.39}/Dockerfile +0 -0
  22. {ingestr-0.13.38 → ingestr-0.13.39}/LICENSE.md +0 -0
  23. {ingestr-0.13.38 → ingestr-0.13.39}/Makefile +0 -0
  24. {ingestr-0.13.38 → ingestr-0.13.39}/README.md +0 -0
  25. {ingestr-0.13.38 → ingestr-0.13.39}/docs/.vitepress/config.mjs +0 -0
  26. {ingestr-0.13.38 → ingestr-0.13.39}/docs/.vitepress/theme/custom.css +0 -0
  27. {ingestr-0.13.38 → ingestr-0.13.39}/docs/.vitepress/theme/index.js +0 -0
  28. {ingestr-0.13.38 → ingestr-0.13.39}/docs/commands/example-uris.md +0 -0
  29. {ingestr-0.13.38 → ingestr-0.13.39}/docs/commands/ingest.md +0 -0
  30. {ingestr-0.13.38 → ingestr-0.13.39}/docs/getting-started/core-concepts.md +0 -0
  31. {ingestr-0.13.38 → ingestr-0.13.39}/docs/getting-started/incremental-loading.md +0 -0
  32. {ingestr-0.13.38 → ingestr-0.13.39}/docs/getting-started/quickstart.md +0 -0
  33. {ingestr-0.13.38 → ingestr-0.13.39}/docs/getting-started/telemetry.md +0 -0
  34. {ingestr-0.13.38 → ingestr-0.13.39}/docs/index.md +0 -0
  35. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/applovin_max.png +0 -0
  36. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/athena.png +0 -0
  37. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/clickhouse_img.png +0 -0
  38. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/freshdesk_ingestion.png +0 -0
  39. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/github.png +0 -0
  40. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/google_analytics_realtime_report.png +0 -0
  41. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/googleanalytics.png +0 -0
  42. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/kinesis.bigquery.png +0 -0
  43. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/linkedin_ads.png +0 -0
  44. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/personio.png +0 -0
  45. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/personio_duckdb.png +0 -0
  46. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/phantombuster.png +0 -0
  47. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/pipedrive.png +0 -0
  48. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/stripe_postgres.png +0 -0
  49. {ingestr-0.13.38 → ingestr-0.13.39}/docs/media/tiktok.png +0 -0
  50. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/adjust.md +0 -0
  51. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/airtable.md +0 -0
  52. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/applovin.md +0 -0
  53. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/applovin_max.md +0 -0
  54. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/appsflyer.md +0 -0
  55. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/appstore.md +0 -0
  56. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/asana.md +0 -0
  57. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/athena.md +0 -0
  58. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/bigquery.md +0 -0
  59. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/chess.md +0 -0
  60. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/clickhouse.md +0 -0
  61. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/csv.md +0 -0
  62. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/custom_queries.md +0 -0
  63. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/databricks.md +0 -0
  64. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/db2.md +0 -0
  65. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/duckdb.md +0 -0
  66. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/dynamodb.md +0 -0
  67. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/facebook-ads.md +0 -0
  68. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/frankfurter.md +0 -0
  69. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/freshdesk.md +0 -0
  70. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/gcs.md +0 -0
  71. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/github.md +0 -0
  72. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/google-ads.md +0 -0
  73. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/google_analytics.md +0 -0
  74. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/gorgias.md +0 -0
  75. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/gsheets.md +0 -0
  76. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/hubspot.md +0 -0
  77. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/kafka.md +0 -0
  78. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/kinesis.md +0 -0
  79. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/klaviyo.md +0 -0
  80. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/linkedin_ads.md +0 -0
  81. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/mongodb.md +0 -0
  82. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/mssql.md +0 -0
  83. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/mysql.md +0 -0
  84. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/notion.md +0 -0
  85. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/oracle.md +0 -0
  86. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/personio.md +0 -0
  87. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/phantombuster.md +0 -0
  88. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/pipedrive.md +0 -0
  89. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/postgres.md +0 -0
  90. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/redshift.md +0 -0
  91. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/s3.md +0 -0
  92. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/salesforce.md +0 -0
  93. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/sap-hana.md +0 -0
  94. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/shopify.md +0 -0
  95. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/slack.md +0 -0
  96. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/snowflake.md +0 -0
  97. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/sqlite.md +0 -0
  98. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/stripe.md +0 -0
  99. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/tiktok-ads.md +0 -0
  100. {ingestr-0.13.38 → ingestr-0.13.39}/docs/supported-sources/zendesk.md +0 -0
  101. {ingestr-0.13.38 → ingestr-0.13.39}/docs/tutorials/load-kinesis-bigquery.md +0 -0
  102. {ingestr-0.13.38 → ingestr-0.13.39}/docs/tutorials/load-personio-duckdb.md +0 -0
  103. {ingestr-0.13.38 → ingestr-0.13.39}/docs/tutorials/load-stripe-postgres.md +0 -0
  104. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/conftest.py +0 -0
  105. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/.gitignore +0 -0
  106. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/adjust/__init__.py +0 -0
  107. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/adjust/adjust_helpers.py +0 -0
  108. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/airtable/__init__.py +0 -0
  109. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/applovin/__init__.py +0 -0
  110. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/applovin_max/__init__.py +0 -0
  111. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/appsflyer/__init__.py +0 -0
  112. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/appsflyer/client.py +0 -0
  113. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/appstore/__init__.py +0 -0
  114. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/appstore/client.py +0 -0
  115. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/appstore/errors.py +0 -0
  116. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/appstore/models.py +0 -0
  117. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/appstore/resources.py +0 -0
  118. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/arrow/__init__.py +0 -0
  119. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/asana_source/__init__.py +0 -0
  120. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/asana_source/helpers.py +0 -0
  121. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/asana_source/settings.py +0 -0
  122. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/blob.py +0 -0
  123. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/chess/__init__.py +0 -0
  124. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/chess/helpers.py +0 -0
  125. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/chess/settings.py +0 -0
  126. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/collector/spinner.py +0 -0
  127. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/dynamodb/__init__.py +0 -0
  128. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/errors.py +0 -0
  129. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/facebook_ads/__init__.py +0 -0
  130. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/facebook_ads/exceptions.py +0 -0
  131. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/facebook_ads/helpers.py +0 -0
  132. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/facebook_ads/settings.py +0 -0
  133. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/filesystem/__init__.py +0 -0
  134. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/filesystem/helpers.py +0 -0
  135. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/filesystem/readers.py +0 -0
  136. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/filters.py +0 -0
  137. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/frankfurter/__init__.py +0 -0
  138. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/frankfurter/helpers.py +0 -0
  139. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/freshdesk/__init__.py +0 -0
  140. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/freshdesk/freshdesk_client.py +0 -0
  141. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/freshdesk/settings.py +0 -0
  142. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/github/__init__.py +0 -0
  143. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/github/helpers.py +0 -0
  144. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/github/queries.py +0 -0
  145. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/github/settings.py +0 -0
  146. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/google_ads/__init__.py +0 -0
  147. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/google_ads/field.py +0 -0
  148. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/google_ads/metrics.py +0 -0
  149. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/google_ads/predicates.py +0 -0
  150. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/google_ads/reports.py +0 -0
  151. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/google_analytics/__init__.py +0 -0
  152. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/google_sheets/README.md +0 -0
  153. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/google_sheets/__init__.py +0 -0
  154. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/google_sheets/helpers/__init__.py +0 -0
  155. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/google_sheets/helpers/api_calls.py +0 -0
  156. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/google_sheets/helpers/data_processing.py +0 -0
  157. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/gorgias/__init__.py +0 -0
  158. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/gorgias/helpers.py +0 -0
  159. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/hubspot/__init__.py +0 -0
  160. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/hubspot/helpers.py +0 -0
  161. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/hubspot/settings.py +0 -0
  162. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/kafka/__init__.py +0 -0
  163. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/kafka/helpers.py +0 -0
  164. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/kinesis/__init__.py +0 -0
  165. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/kinesis/helpers.py +0 -0
  166. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/klaviyo/__init__.py +0 -0
  167. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/klaviyo/client.py +0 -0
  168. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/klaviyo/helpers.py +0 -0
  169. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/linkedin_ads/__init__.py +0 -0
  170. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/linkedin_ads/dimension_time_enum.py +0 -0
  171. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/linkedin_ads/helpers.py +0 -0
  172. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/loader.py +0 -0
  173. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/mongodb/__init__.py +0 -0
  174. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/mongodb/helpers.py +0 -0
  175. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/notion/__init__.py +0 -0
  176. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/notion/helpers/__init__.py +0 -0
  177. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/notion/helpers/client.py +0 -0
  178. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/notion/helpers/database.py +0 -0
  179. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/notion/settings.py +0 -0
  180. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/partition.py +0 -0
  181. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/personio/__init__.py +0 -0
  182. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/personio/helpers.py +0 -0
  183. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/pipedrive/__init__.py +0 -0
  184. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/pipedrive/helpers/__init__.py +0 -0
  185. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/pipedrive/helpers/custom_fields_munger.py +0 -0
  186. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/pipedrive/helpers/pages.py +0 -0
  187. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/pipedrive/settings.py +0 -0
  188. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/pipedrive/typing.py +0 -0
  189. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/resource.py +0 -0
  190. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/salesforce/__init__.py +0 -0
  191. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/salesforce/helpers.py +0 -0
  192. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/shopify/__init__.py +0 -0
  193. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/shopify/exceptions.py +0 -0
  194. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/shopify/helpers.py +0 -0
  195. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/shopify/settings.py +0 -0
  196. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/slack/__init__.py +0 -0
  197. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/slack/helpers.py +0 -0
  198. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/slack/settings.py +0 -0
  199. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/sql_database/__init__.py +0 -0
  200. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/sql_database/callbacks.py +0 -0
  201. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/stripe_analytics/__init__.py +0 -0
  202. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/stripe_analytics/helpers.py +0 -0
  203. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/stripe_analytics/settings.py +0 -0
  204. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/table_definition.py +0 -0
  205. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/telemetry/event.py +0 -0
  206. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/testdata/fakebqcredentials.json +0 -0
  207. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/tiktok_ads/__init__.py +0 -0
  208. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/tiktok_ads/tiktok_helpers.py +0 -0
  209. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/time.py +0 -0
  210. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/version.py +0 -0
  211. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/zendesk/__init__.py +0 -0
  212. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/zendesk/helpers/__init__.py +0 -0
  213. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/zendesk/helpers/api_helpers.py +0 -0
  214. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/zendesk/helpers/credentials.py +0 -0
  215. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/zendesk/helpers/talk_api.py +0 -0
  216. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/src/zendesk/settings.py +0 -0
  217. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/testdata/.gitignore +0 -0
  218. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/testdata/create_replace.csv +0 -0
  219. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/testdata/delete_insert_expected.csv +0 -0
  220. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/testdata/delete_insert_part1.csv +0 -0
  221. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/testdata/delete_insert_part2.csv +0 -0
  222. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/testdata/merge_expected.csv +0 -0
  223. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/testdata/merge_part1.csv +0 -0
  224. {ingestr-0.13.38 → ingestr-0.13.39}/ingestr/testdata/merge_part2.csv +0 -0
  225. {ingestr-0.13.38 → ingestr-0.13.39}/package-lock.json +0 -0
  226. {ingestr-0.13.38 → ingestr-0.13.39}/package.json +0 -0
  227. {ingestr-0.13.38 → ingestr-0.13.39}/pyproject.toml +0 -0
  228. {ingestr-0.13.38 → ingestr-0.13.39}/requirements-dev.txt +0 -0
  229. {ingestr-0.13.38 → ingestr-0.13.39}/requirements.in +0 -0
  230. {ingestr-0.13.38 → ingestr-0.13.39}/requirements.txt +0 -0
  231. {ingestr-0.13.38 → ingestr-0.13.39}/requirements_arm64.txt +0 -0
  232. {ingestr-0.13.38 → ingestr-0.13.39}/resources/demo.gif +0 -0
  233. {ingestr-0.13.38 → ingestr-0.13.39}/resources/demo.tape +0 -0
  234. {ingestr-0.13.38 → ingestr-0.13.39}/resources/ingestr.svg +0 -0
  235. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/AMPM.yml +0 -0
  236. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Acronyms.yml +0 -0
  237. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Colons.yml +0 -0
  238. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Contractions.yml +0 -0
  239. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/DateFormat.yml +0 -0
  240. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Ellipses.yml +0 -0
  241. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/EmDash.yml +0 -0
  242. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Exclamation.yml +0 -0
  243. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/FirstPerson.yml +0 -0
  244. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Gender.yml +0 -0
  245. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/GenderBias.yml +0 -0
  246. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/HeadingPunctuation.yml +0 -0
  247. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Headings.yml +0 -0
  248. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Latin.yml +0 -0
  249. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/LyHyphens.yml +0 -0
  250. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/OptionalPlurals.yml +0 -0
  251. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Ordinal.yml +0 -0
  252. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/OxfordComma.yml +0 -0
  253. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Parens.yml +0 -0
  254. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Passive.yml +0 -0
  255. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Periods.yml +0 -0
  256. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Quotes.yml +0 -0
  257. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Ranges.yml +0 -0
  258. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Semicolons.yml +0 -0
  259. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Slang.yml +0 -0
  260. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Spacing.yml +0 -0
  261. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Spelling.yml +0 -0
  262. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Units.yml +0 -0
  263. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/We.yml +0 -0
  264. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/Will.yml +0 -0
  265. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/WordList.yml +0 -0
  266. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/meta.json +0 -0
  267. {ingestr-0.13.38 → ingestr-0.13.39}/styles/Google/vocab.txt +0 -0
  268. {ingestr-0.13.38 → ingestr-0.13.39}/styles/bruin/Ingestr.yml +0 -0
  269. {ingestr-0.13.38 → ingestr-0.13.39}/styles/config/vocabularies/bruin/accept.txt +0 -0
  270. {ingestr-0.13.38 → ingestr-0.13.39}/test.env.template +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ingestr
3
- Version: 0.13.38
3
+ Version: 0.13.39
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
@@ -34,6 +34,7 @@ PARQUET_SUPPORTED_DESTINATIONS = [
34
34
  "snowflake",
35
35
  "databricks",
36
36
  "synapse",
37
+ "s3",
37
38
  ]
38
39
 
39
40
  # these sources would return a JSON for sure, which means they cannot be used with Parquet loader for BigQuery
@@ -485,9 +486,7 @@ def ingest(
485
486
  print(
486
487
  f"[bold yellow] Primary Key:[/bold yellow] {primary_key if primary_key else 'None'}"
487
488
  )
488
- print(
489
- f"[bold yellow] Pipeline ID:[/bold yellow] {m.hexdigest()}"
490
- )
489
+ print(f"[bold yellow] Pipeline ID:[/bold yellow] {m.hexdigest()}")
491
490
  print()
492
491
 
493
492
  if not yes:
@@ -0,0 +1 @@
1
+ version = "v0.13.39"
@@ -7,11 +7,13 @@ import tempfile
7
7
  from urllib.parse import parse_qs, quote, urlparse
8
8
 
9
9
  import dlt
10
+ import dlt.destinations.impl.filesystem.filesystem
10
11
  from dlt.common.configuration.specs import AwsCredentials
11
12
  from dlt.destinations.impl.clickhouse.configuration import (
12
13
  ClickHouseCredentials,
13
14
  )
14
15
 
16
+ from ingestr.src.errors import MissingValueError
15
17
  from ingestr.src.loader import load_dlt_file
16
18
 
17
19
 
@@ -382,3 +384,71 @@ class ClickhouseDestination:
382
384
 
383
385
  def post_load(self):
384
386
  pass
387
+
388
+
389
+ class S3FSClient(dlt.destinations.impl.filesystem.filesystem.FilesystemClient):
390
+ @property
391
+ def dataset_path(self):
392
+ # override to remove dataset path
393
+ return self.bucket_path
394
+
395
+
396
+ class S3FS(dlt.destinations.filesystem):
397
+ @property
398
+ def client_class(self):
399
+ return S3FSClient
400
+
401
+
402
+ class S3Destination:
403
+ def dlt_dest(self, uri: str, **kwargs):
404
+ parsed_uri = urlparse(uri)
405
+ params = parse_qs(parsed_uri.query)
406
+
407
+ access_key_id = params.get("access_key_id", [None])[0]
408
+ if access_key_id is None:
409
+ raise MissingValueError("access_key_id", "S3")
410
+
411
+ secret_access_key = params.get("secret_access_key", [None])[0]
412
+ if secret_access_key is None:
413
+ raise MissingValueError("secret_access_key", "S3")
414
+
415
+ endpoint_url = params.get("endpoint_url", [None])[0]
416
+
417
+ creds = AwsCredentials(
418
+ aws_access_key_id=access_key_id,
419
+ aws_secret_access_key=secret_access_key,
420
+ endpoint_url=endpoint_url,
421
+ )
422
+
423
+ dest_table = self.validate_table(kwargs["dest_table"])
424
+ table_parts = dest_table.split("/")
425
+ base_path = "/".join(table_parts[:-1])
426
+
427
+ opts = {
428
+ "bucket_url": f"s3://{base_path}",
429
+ "credentials": creds,
430
+ # supresses dlt warnings about dataset name normalization.
431
+ # we don't use dataset names in S3 so it's fine to disable this.
432
+ "enable_dataset_name_normalization": False,
433
+ }
434
+ layout = params.get("layout", [None])[0]
435
+ if layout is not None:
436
+ opts["layout"] = layout
437
+
438
+ return S3FS(**opts) # type: ignore
439
+
440
+ def validate_table(self, table: str):
441
+ table = table.strip("/ ")
442
+ if len(table.split("/")) < 2:
443
+ raise ValueError("Table name must be in the format {bucket-name}/{path}")
444
+ return table
445
+
446
+ def dlt_run_params(self, uri: str, table: str, **kwargs):
447
+ table = self.validate_table(table)
448
+ table_parts = table.split("/")
449
+ return {
450
+ "table_name": table_parts[-1],
451
+ }
452
+
453
+ def post_load(self) -> None:
454
+ pass
@@ -13,6 +13,7 @@ from ingestr.src.destinations import (
13
13
  MsSQLDestination,
14
14
  PostgresDestination,
15
15
  RedshiftDestination,
16
+ S3Destination,
16
17
  SnowflakeDestination,
17
18
  SynapseDestination,
18
19
  )
@@ -29,6 +30,7 @@ from ingestr.src.sources import (
29
30
  DynamoDBSource,
30
31
  FacebookAdsSource,
31
32
  FrankfurterSource,
33
+ FreshdeskSource,
32
34
  GCSSource,
33
35
  GitHubSource,
34
36
  GoogleAdsSource,
@@ -44,6 +46,7 @@ from ingestr.src.sources import (
44
46
  MongoDbSource,
45
47
  NotionSource,
46
48
  PersonioSource,
49
+ PhantombusterSource,
47
50
  PipedriveSource,
48
51
  S3Source,
49
52
  SalesforceSource,
@@ -53,8 +56,6 @@ from ingestr.src.sources import (
53
56
  StripeAnalyticsSource,
54
57
  TikTokSource,
55
58
  ZendeskSource,
56
- FreshdeskSource,
57
- PhantombusterSource,
58
59
  )
59
60
 
60
61
  SQL_SOURCE_SCHEMES = [
@@ -170,6 +171,7 @@ class SourceDestinationFactory:
170
171
  "athena": AthenaDestination,
171
172
  "clickhouse+native": ClickhouseDestination,
172
173
  "clickhouse": ClickhouseDestination,
174
+ "s3": S3Destination,
173
175
  }
174
176
 
175
177
  def __init__(self, source_uri: str, destination_uri: str):
@@ -149,7 +149,7 @@ def get_report(
149
149
 
150
150
  # process request
151
151
  processed_response_generator = process_report(response=response)
152
-
152
+
153
153
  # import pdb; pdb.set_trace()
154
154
  yield from processed_response_generator
155
155
  offset += per_page
@@ -225,7 +225,9 @@ def _resolve_dimension_value(dimension_name: str, dimension_value: str) -> Any:
225
225
  return dimension_value
226
226
 
227
227
 
228
- def convert_minutes_ranges_to_minute_range_objects(minutes_ranges: str) -> List[MinuteRange]:
228
+ def convert_minutes_ranges_to_minute_range_objects(
229
+ minutes_ranges: str,
230
+ ) -> List[MinuteRange]:
229
231
  minutes_ranges = minutes_ranges.strip()
230
232
  minutes = minutes_ranges.replace(" ", "").split(",")
231
233
  if minutes == "":
@@ -233,7 +235,6 @@ def convert_minutes_ranges_to_minute_range_objects(minutes_ranges: str) -> List[
233
235
  "Invalid input. Minutes range should be startminute-endminute format. For example: 1-2,5-6"
234
236
  )
235
237
 
236
-
237
238
  minute_range_objects = []
238
239
  for min_range in minutes:
239
240
  if "-" not in min_range:
@@ -246,14 +247,16 @@ def convert_minutes_ranges_to_minute_range_objects(minutes_ranges: str) -> List[
246
247
  raise ValueError(
247
248
  f"Invalid input '{min_range}'. Both start and end minutes must be digits. For example: 1-2,5-6"
248
249
  )
249
-
250
+
250
251
  end_minutes_ago = int(parts[0])
251
252
  start_minutes_ago = int(parts[1])
252
- minute_range_objects.append(MinuteRange(
253
- name=f"{end_minutes_ago}-{start_minutes_ago} minutes ago",
254
- start_minutes_ago= start_minutes_ago,
255
- end_minutes_ago=end_minutes_ago
256
- ))
253
+ minute_range_objects.append(
254
+ MinuteRange(
255
+ name=f"{end_minutes_ago}-{start_minutes_ago} minutes ago",
256
+ start_minutes_ago=start_minutes_ago,
257
+ end_minutes_ago=end_minutes_ago,
258
+ )
259
+ )
257
260
 
258
261
  return minute_range_objects
259
262
 
@@ -3,11 +3,10 @@ from typing import Iterable, Optional
3
3
  import dlt
4
4
  import pendulum
5
5
  import requests
6
- from dlt.common.typing import TDataItem, TAnyDateTime
6
+ from dlt.common.typing import TAnyDateTime, TDataItem
7
7
  from dlt.sources import DltResource
8
8
  from dlt.sources.helpers.requests import Client
9
9
 
10
-
11
10
  from ingestr.src.phantombuster.client import PhantombusterClient
12
11
 
13
12
 
@@ -27,9 +26,13 @@ def create_client() -> requests.Session:
27
26
  request_backoff_factor=2,
28
27
  ).session
29
28
 
29
+
30
30
  @dlt.source(max_table_nesting=0)
31
- def phantombuster_source(api_key: str, agent_id: str, start_date: TAnyDateTime, end_date: TAnyDateTime | None) -> Iterable[DltResource]:
31
+ def phantombuster_source(
32
+ api_key: str, agent_id: str, start_date: TAnyDateTime, end_date: TAnyDateTime | None
33
+ ) -> Iterable[DltResource]:
32
34
  client = PhantombusterClient(api_key)
35
+
33
36
  @dlt.resource(
34
37
  write_disposition="merge",
35
38
  primary_key="container_id",
@@ -55,6 +58,8 @@ def phantombuster_source(api_key: str, agent_id: str, start_date: TAnyDateTime,
55
58
 
56
59
  start_dt = dateTime.last_value
57
60
 
58
- yield client.fetch_containers_result(create_client(), agent_id, start_date=start_dt, end_date=end_dt)
61
+ yield client.fetch_containers_result(
62
+ create_client(), agent_id, start_date=start_dt, end_date=end_dt
63
+ )
59
64
 
60
65
  return completed_phantoms
@@ -14,14 +14,22 @@ class PhantombusterClient:
14
14
  "accept": "application/json",
15
15
  }
16
16
 
17
- def fetch_containers_result(self, session: requests.Session, agent_id: str, start_date: pendulum.DateTime, end_date: pendulum.DateTime):
17
+ def fetch_containers_result(
18
+ self,
19
+ session: requests.Session,
20
+ agent_id: str,
21
+ start_date: pendulum.DateTime,
22
+ end_date: pendulum.DateTime,
23
+ ):
18
24
  url = "https://api.phantombuster.com/api/v2/containers/fetch-all/"
19
25
  before_ended_at = None
20
26
  limit = 100
21
27
 
22
- started_at = start_date.int_timestamp * 1000 + int(start_date.microsecond / 1000)
28
+ started_at = start_date.int_timestamp * 1000 + int(
29
+ start_date.microsecond / 1000
30
+ )
23
31
  ended_at = end_date.int_timestamp * 1000 + int(end_date.microsecond / 1000)
24
-
32
+
25
33
  while True:
26
34
  params: dict[str, Union[str, int, float, bytes, None]] = {
27
35
  "agentId": agent_id,
@@ -40,24 +48,33 @@ class PhantombusterClient:
40
48
  container_ended_at = container.get("endedAt")
41
49
 
42
50
  if before_ended_at is None or before_ended_at > container_ended_at:
43
- before_ended_at = container_ended_at
44
-
51
+ before_ended_at = container_ended_at
52
+
45
53
  if container_ended_at < started_at or container_ended_at > ended_at:
46
54
  continue
47
-
55
+
48
56
  try:
49
57
  result = self.fetch_result_object(session, container["id"])
50
- partition_dt = pendulum.from_timestamp(container_ended_at / 1000, tz="UTC").date()
51
- container_ended_at_datetime = pendulum.from_timestamp(container_ended_at / 1000, tz="UTC")
52
- row = {"container_id": container["id"],"container": container, "result": result, "partition_dt": partition_dt, "ended_at": container_ended_at_datetime}
58
+ partition_dt = pendulum.from_timestamp(
59
+ container_ended_at / 1000, tz="UTC"
60
+ ).date()
61
+ container_ended_at_datetime = pendulum.from_timestamp(
62
+ container_ended_at / 1000, tz="UTC"
63
+ )
64
+ row = {
65
+ "container_id": container["id"],
66
+ "container": container,
67
+ "result": result,
68
+ "partition_dt": partition_dt,
69
+ "ended_at": container_ended_at_datetime,
70
+ }
53
71
  yield row
54
-
72
+
55
73
  except requests.RequestException as e:
56
74
  print(f"Error fetching result for container {container['id']}: {e}")
57
-
75
+
58
76
  if data["maxLimitReached"] is False:
59
77
  break
60
-
61
78
 
62
79
  def fetch_result_object(self, session: requests.Session, container_id: str):
63
80
  result_url = (
@@ -1492,7 +1492,9 @@ class GoogleAnalyticsSource:
1492
1492
 
1493
1493
  minute_range_objects = []
1494
1494
  if len(fields) == 4:
1495
- minute_range_objects = helpers.convert_minutes_ranges_to_minute_range_objects(fields[3])
1495
+ minute_range_objects = (
1496
+ helpers.convert_minutes_ranges_to_minute_range_objects(fields[3])
1497
+ )
1496
1498
 
1497
1499
  datetime = ""
1498
1500
  resource_name = fields[0].lower()
@@ -2217,10 +2219,10 @@ class FrankfurterSource:
2217
2219
 
2218
2220
 
2219
2221
  class FreshdeskSource:
2220
- # freshdesk://domain?api_key=<api_key>
2222
+ # freshdesk://domain?api_key=<api_key>
2221
2223
  def handles_incrementality(self) -> bool:
2222
2224
  return True
2223
-
2225
+
2224
2226
  def dlt_source(self, uri: str, table: str, **kwargs):
2225
2227
  parsed_uri = urlparse(uri)
2226
2228
  domain = parsed_uri.netloc
@@ -2230,43 +2232,54 @@ class FreshdeskSource:
2230
2232
  if not domain:
2231
2233
  raise MissingValueError("domain", "Freshdesk")
2232
2234
 
2233
- if '.' in domain:
2234
- domain = domain.split('.')[0]
2235
-
2235
+ if "." in domain:
2236
+ domain = domain.split(".")[0]
2237
+
2236
2238
  api_key = params.get("api_key")
2237
2239
  if api_key is None:
2238
2240
  raise MissingValueError("api_key", "Freshdesk")
2239
-
2240
- if table not in ["agents", "companies", "contacts", "groups", "roles", "tickets"]:
2241
+
2242
+ if table not in [
2243
+ "agents",
2244
+ "companies",
2245
+ "contacts",
2246
+ "groups",
2247
+ "roles",
2248
+ "tickets",
2249
+ ]:
2241
2250
  raise UnsupportedResourceError(table, "Freshdesk")
2242
-
2251
+
2243
2252
  from ingestr.src.freshdesk import freshdesk_source
2244
- return freshdesk_source(api_secret_key=api_key[0], domain=domain).with_resources(table)
2253
+
2254
+ return freshdesk_source(
2255
+ api_secret_key=api_key[0], domain=domain
2256
+ ).with_resources(table)
2257
+
2245
2258
 
2246
2259
  class PhantombusterSource:
2247
2260
  def handles_incrementality(self) -> bool:
2248
2261
  return True
2249
-
2262
+
2250
2263
  def dlt_source(self, uri: str, table: str, **kwargs):
2251
- #phantombuster://?api_key=<api_key>
2252
- #source table = phantom_results:agent_id
2264
+ # phantombuster://?api_key=<api_key>
2265
+ # source table = phantom_results:agent_id
2253
2266
  parsed_uri = urlparse(uri)
2254
2267
  params = parse_qs(parsed_uri.query)
2255
2268
  api_key = params.get("api_key")
2256
2269
  if api_key is None:
2257
2270
  raise MissingValueError("api_key", "Phantombuster")
2258
-
2271
+
2259
2272
  table_fields = table.replace(" ", "").split(":")
2260
2273
  table_name = table_fields[0]
2261
-
2274
+
2262
2275
  agent_id = table_fields[1] if len(table_fields) > 1 else None
2263
-
2276
+
2264
2277
  if table_name not in ["completed_phantoms"]:
2265
2278
  raise UnsupportedResourceError(table_name, "Phantombuster")
2266
-
2279
+
2267
2280
  if not agent_id:
2268
2281
  raise MissingValueError("agent_id", "Phantombuster")
2269
-
2282
+
2270
2283
  start_date = kwargs.get("interval_start")
2271
2284
  if start_date is None:
2272
2285
  start_date = ensure_pendulum_datetime("2018-01-01").in_tz("UTC")
@@ -2276,6 +2289,12 @@ class PhantombusterSource:
2276
2289
  end_date = kwargs.get("interval_end")
2277
2290
  if end_date is not None:
2278
2291
  end_date = ensure_pendulum_datetime(end_date).in_tz("UTC")
2279
-
2292
+
2280
2293
  from ingestr.src.phantombuster import phantombuster_source
2281
- return phantombuster_source(api_key=api_key[0], agent_id=agent_id, start_date=start_date, end_date=end_date).with_resources(table_name)
2294
+
2295
+ return phantombuster_source(
2296
+ api_key=api_key[0],
2297
+ agent_id=agent_id,
2298
+ start_date=start_date,
2299
+ end_date=end_date,
2300
+ ).with_resources(table_name)
@@ -1 +0,0 @@
1
- version = "v0.13.38"
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