outhad-integrations 0.32.0

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.
Files changed (275) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +43 -0
  4. data/.ruby-version +1 -0
  5. data/.vscode/settings.json +5 -0
  6. data/README.md +76 -0
  7. data/Rakefile +12 -0
  8. data/lib/outhad/integrations/config.rb +14 -0
  9. data/lib/outhad/integrations/core/base_connector.rb +79 -0
  10. data/lib/outhad/integrations/core/constants.rb +103 -0
  11. data/lib/outhad/integrations/core/destination_connector.rb +20 -0
  12. data/lib/outhad/integrations/core/fullrefresher.rb +19 -0
  13. data/lib/outhad/integrations/core/http_client.rb +17 -0
  14. data/lib/outhad/integrations/core/http_helper.rb +36 -0
  15. data/lib/outhad/integrations/core/query_builder.rb +33 -0
  16. data/lib/outhad/integrations/core/rate_limiter.rb +19 -0
  17. data/lib/outhad/integrations/core/source_connector.rb +66 -0
  18. data/lib/outhad/integrations/core/streaming_http_client.rb +21 -0
  19. data/lib/outhad/integrations/core/unstructured_source_connector.rb +52 -0
  20. data/lib/outhad/integrations/core/utils.rb +123 -0
  21. data/lib/outhad/integrations/core/vector_source_connector.rb +14 -0
  22. data/lib/outhad/integrations/destination/airtable/client.rb +157 -0
  23. data/lib/outhad/integrations/destination/airtable/config/catalog.json +6 -0
  24. data/lib/outhad/integrations/destination/airtable/config/meta.json +15 -0
  25. data/lib/outhad/integrations/destination/airtable/config/spec.json +23 -0
  26. data/lib/outhad/integrations/destination/airtable/icon.svg +6 -0
  27. data/lib/outhad/integrations/destination/airtable/schema_helper.rb +141 -0
  28. data/lib/outhad/integrations/destination/ais_data_store/client.rb +130 -0
  29. data/lib/outhad/integrations/destination/ais_data_store/config/meta.json +15 -0
  30. data/lib/outhad/integrations/destination/ais_data_store/config/spec.json +68 -0
  31. data/lib/outhad/integrations/destination/ais_data_store/icon.svg +4 -0
  32. data/lib/outhad/integrations/destination/amazon_s3/client.rb +92 -0
  33. data/lib/outhad/integrations/destination/amazon_s3/config/catalog.json +16 -0
  34. data/lib/outhad/integrations/destination/amazon_s3/config/meta.json +15 -0
  35. data/lib/outhad/integrations/destination/amazon_s3/config/spec.json +56 -0
  36. data/lib/outhad/integrations/destination/amazon_s3/icon.svg +34 -0
  37. data/lib/outhad/integrations/destination/databricks_lakehouse/client.rb +147 -0
  38. data/lib/outhad/integrations/destination/databricks_lakehouse/config/meta.json +15 -0
  39. data/lib/outhad/integrations/destination/databricks_lakehouse/config/spec.json +44 -0
  40. data/lib/outhad/integrations/destination/databricks_lakehouse/icon.svg +65 -0
  41. data/lib/outhad/integrations/destination/facebook_custom_audience/client.rb +125 -0
  42. data/lib/outhad/integrations/destination/facebook_custom_audience/config/catalog.json +42 -0
  43. data/lib/outhad/integrations/destination/facebook_custom_audience/config/meta.json +15 -0
  44. data/lib/outhad/integrations/destination/facebook_custom_audience/config/spec.json +28 -0
  45. data/lib/outhad/integrations/destination/facebook_custom_audience/icon.svg +23 -0
  46. data/lib/outhad/integrations/destination/google_sheets/client.rb +240 -0
  47. data/lib/outhad/integrations/destination/google_sheets/config/catalog.json +6 -0
  48. data/lib/outhad/integrations/destination/google_sheets/config/meta.json +15 -0
  49. data/lib/outhad/integrations/destination/google_sheets/config/spec.json +75 -0
  50. data/lib/outhad/integrations/destination/google_sheets/icon.svg +1 -0
  51. data/lib/outhad/integrations/destination/http/client.rb +106 -0
  52. data/lib/outhad/integrations/destination/http/config/catalog.json +16 -0
  53. data/lib/outhad/integrations/destination/http/config/meta.json +15 -0
  54. data/lib/outhad/integrations/destination/http/config/spec.json +24 -0
  55. data/lib/outhad/integrations/destination/http/icon.svg +9 -0
  56. data/lib/outhad/integrations/destination/hubspot/client.rb +122 -0
  57. data/lib/outhad/integrations/destination/hubspot/config/catalog.json +351 -0
  58. data/lib/outhad/integrations/destination/hubspot/config/meta.json +15 -0
  59. data/lib/outhad/integrations/destination/hubspot/config/spec.json +18 -0
  60. data/lib/outhad/integrations/destination/hubspot/icon.svg +5 -0
  61. data/lib/outhad/integrations/destination/iterable/client.rb +111 -0
  62. data/lib/outhad/integrations/destination/iterable/config/catalog.json +47 -0
  63. data/lib/outhad/integrations/destination/iterable/config/meta.json +15 -0
  64. data/lib/outhad/integrations/destination/iterable/config/spec.json +19 -0
  65. data/lib/outhad/integrations/destination/iterable/icon.svg +71 -0
  66. data/lib/outhad/integrations/destination/klaviyo/client.rb +119 -0
  67. data/lib/outhad/integrations/destination/klaviyo/config/catalog.json +103 -0
  68. data/lib/outhad/integrations/destination/klaviyo/config/meta.json +15 -0
  69. data/lib/outhad/integrations/destination/klaviyo/config/spec.json +24 -0
  70. data/lib/outhad/integrations/destination/klaviyo/icon.svg +6 -0
  71. data/lib/outhad/integrations/destination/mailchimp/client.rb +141 -0
  72. data/lib/outhad/integrations/destination/mailchimp/config/catalog.json +142 -0
  73. data/lib/outhad/integrations/destination/mailchimp/config/meta.json +15 -0
  74. data/lib/outhad/integrations/destination/mailchimp/config/spec.json +28 -0
  75. data/lib/outhad/integrations/destination/mailchimp/icon.svg +4 -0
  76. data/lib/outhad/integrations/destination/maria_db/client.rb +114 -0
  77. data/lib/outhad/integrations/destination/maria_db/config/meta.json +15 -0
  78. data/lib/outhad/integrations/destination/maria_db/config/spec.json +48 -0
  79. data/lib/outhad/integrations/destination/maria_db/icon.svg +15 -0
  80. data/lib/outhad/integrations/destination/microsoft_dynamics/client.rb +150 -0
  81. data/lib/outhad/integrations/destination/microsoft_dynamics/config/catalog.json +161 -0
  82. data/lib/outhad/integrations/destination/microsoft_dynamics/config/meta.json +15 -0
  83. data/lib/outhad/integrations/destination/microsoft_dynamics/config/spec.json +35 -0
  84. data/lib/outhad/integrations/destination/microsoft_dynamics/icon.svg +2 -0
  85. data/lib/outhad/integrations/destination/microsoft_excel/client.rb +198 -0
  86. data/lib/outhad/integrations/destination/microsoft_excel/config/catalog.json +7 -0
  87. data/lib/outhad/integrations/destination/microsoft_excel/config/meta.json +15 -0
  88. data/lib/outhad/integrations/destination/microsoft_excel/config/spec.json +19 -0
  89. data/lib/outhad/integrations/destination/microsoft_excel/icon.svg +18 -0
  90. data/lib/outhad/integrations/destination/microsoft_sql/client.rb +137 -0
  91. data/lib/outhad/integrations/destination/microsoft_sql/config/meta.json +15 -0
  92. data/lib/outhad/integrations/destination/microsoft_sql/config/spec.json +68 -0
  93. data/lib/outhad/integrations/destination/microsoft_sql/icon.svg +22 -0
  94. data/lib/outhad/integrations/destination/odoo/client.rb +109 -0
  95. data/lib/outhad/integrations/destination/odoo/config/meta.json +15 -0
  96. data/lib/outhad/integrations/destination/odoo/config/spec.json +39 -0
  97. data/lib/outhad/integrations/destination/odoo/icon.svg +21 -0
  98. data/lib/outhad/integrations/destination/oracle_db/client.rb +112 -0
  99. data/lib/outhad/integrations/destination/oracle_db/config/meta.json +15 -0
  100. data/lib/outhad/integrations/destination/oracle_db/config/spec.json +47 -0
  101. data/lib/outhad/integrations/destination/oracle_db/icon.svg +4 -0
  102. data/lib/outhad/integrations/destination/pinecone_db/client.rb +154 -0
  103. data/lib/outhad/integrations/destination/pinecone_db/config/meta.json +15 -0
  104. data/lib/outhad/integrations/destination/pinecone_db/config/spec.json +32 -0
  105. data/lib/outhad/integrations/destination/pinecone_db/icon.svg +1 -0
  106. data/lib/outhad/integrations/destination/postgresql/client.rb +130 -0
  107. data/lib/outhad/integrations/destination/postgresql/config/meta.json +15 -0
  108. data/lib/outhad/integrations/destination/postgresql/config/spec.json +68 -0
  109. data/lib/outhad/integrations/destination/postgresql/icon.svg +20 -0
  110. data/lib/outhad/integrations/destination/qdrant/client.rb +184 -0
  111. data/lib/outhad/integrations/destination/qdrant/config/meta.json +15 -0
  112. data/lib/outhad/integrations/destination/qdrant/config/spec.json +23 -0
  113. data/lib/outhad/integrations/destination/qdrant/icon.svg +1 -0
  114. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/client.rb +136 -0
  115. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/config/catalog.json +6 -0
  116. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/config/meta.json +16 -0
  117. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/config/spec.json +52 -0
  118. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/icon.svg +16 -0
  119. data/lib/outhad/integrations/destination/salesforce_consumer_goods_cloud/schema_helper.rb +132 -0
  120. data/lib/outhad/integrations/destination/salesforce_crm/client.rb +114 -0
  121. data/lib/outhad/integrations/destination/salesforce_crm/config/catalog.json +320 -0
  122. data/lib/outhad/integrations/destination/salesforce_crm/config/meta.json +15 -0
  123. data/lib/outhad/integrations/destination/salesforce_crm/config/spec.json +46 -0
  124. data/lib/outhad/integrations/destination/salesforce_crm/icon.svg +16 -0
  125. data/lib/outhad/integrations/destination/sftp/client.rb +186 -0
  126. data/lib/outhad/integrations/destination/sftp/config/catalog.json +16 -0
  127. data/lib/outhad/integrations/destination/sftp/config/meta.json +16 -0
  128. data/lib/outhad/integrations/destination/sftp/config/spec.json +73 -0
  129. data/lib/outhad/integrations/destination/sftp/icon.svg +1 -0
  130. data/lib/outhad/integrations/destination/slack/client.rb +125 -0
  131. data/lib/outhad/integrations/destination/slack/config/catalog.json +22 -0
  132. data/lib/outhad/integrations/destination/slack/config/meta.json +15 -0
  133. data/lib/outhad/integrations/destination/slack/config/spec.json +23 -0
  134. data/lib/outhad/integrations/destination/slack/icon.svg +26 -0
  135. data/lib/outhad/integrations/destination/stripe/client.rb +94 -0
  136. data/lib/outhad/integrations/destination/stripe/config/catalog.json +128 -0
  137. data/lib/outhad/integrations/destination/stripe/config/meta.json +15 -0
  138. data/lib/outhad/integrations/destination/stripe/config/spec.json +18 -0
  139. data/lib/outhad/integrations/destination/stripe/icon.svg +10 -0
  140. data/lib/outhad/integrations/destination/zendesk/client.rb +132 -0
  141. data/lib/outhad/integrations/destination/zendesk/config/catalog.json +110 -0
  142. data/lib/outhad/integrations/destination/zendesk/config/meta.json +18 -0
  143. data/lib/outhad/integrations/destination/zendesk/config/spec.json +32 -0
  144. data/lib/outhad/integrations/destination/zendesk/icon.svg +63 -0
  145. data/lib/outhad/integrations/protocol/protocol.json +189 -0
  146. data/lib/outhad/integrations/protocol/protocol.rb +228 -0
  147. data/lib/outhad/integrations/rollout.rb +66 -0
  148. data/lib/outhad/integrations/service.rb +55 -0
  149. data/lib/outhad/integrations/source/amazon_s3/client.rb +235 -0
  150. data/lib/outhad/integrations/source/amazon_s3/config/meta.json +16 -0
  151. data/lib/outhad/integrations/source/amazon_s3/config/spec.json +119 -0
  152. data/lib/outhad/integrations/source/amazon_s3/icon.svg +34 -0
  153. data/lib/outhad/integrations/source/anthropic/client.rb +135 -0
  154. data/lib/outhad/integrations/source/anthropic/config/catalog.json +6 -0
  155. data/lib/outhad/integrations/source/anthropic/config/meta.json +16 -0
  156. data/lib/outhad/integrations/source/anthropic/config/spec.json +56 -0
  157. data/lib/outhad/integrations/source/anthropic/icon.svg +1 -0
  158. data/lib/outhad/integrations/source/aws_athena/client.rb +109 -0
  159. data/lib/outhad/integrations/source/aws_athena/config/meta.json +16 -0
  160. data/lib/outhad/integrations/source/aws_athena/config/spec.json +63 -0
  161. data/lib/outhad/integrations/source/aws_athena/icon.svg +22 -0
  162. data/lib/outhad/integrations/source/aws_bedrock_model/client.rb +91 -0
  163. data/lib/outhad/integrations/source/aws_bedrock_model/config/catalog.json +6 -0
  164. data/lib/outhad/integrations/source/aws_bedrock_model/config/meta.json +16 -0
  165. data/lib/outhad/integrations/source/aws_bedrock_model/config/spec.json +58 -0
  166. data/lib/outhad/integrations/source/aws_bedrock_model/icon.svg +1 -0
  167. data/lib/outhad/integrations/source/aws_sagemaker_model/client.rb +79 -0
  168. data/lib/outhad/integrations/source/aws_sagemaker_model/config/catalog.json +6 -0
  169. data/lib/outhad/integrations/source/aws_sagemaker_model/config/meta.json +16 -0
  170. data/lib/outhad/integrations/source/aws_sagemaker_model/config/spec.json +52 -0
  171. data/lib/outhad/integrations/source/aws_sagemaker_model/icon.svg +7 -0
  172. data/lib/outhad/integrations/source/bigquery/client.rb +98 -0
  173. data/lib/outhad/integrations/source/bigquery/config/meta.json +16 -0
  174. data/lib/outhad/integrations/source/bigquery/config/spec.json +83 -0
  175. data/lib/outhad/integrations/source/bigquery/icon.svg +1 -0
  176. data/lib/outhad/integrations/source/clickhouse/client.rb +102 -0
  177. data/lib/outhad/integrations/source/clickhouse/config/meta.json +16 -0
  178. data/lib/outhad/integrations/source/clickhouse/config/spec.json +42 -0
  179. data/lib/outhad/integrations/source/clickhouse/icon.svg +25 -0
  180. data/lib/outhad/integrations/source/databricks/client.rb +98 -0
  181. data/lib/outhad/integrations/source/databricks/config/meta.json +17 -0
  182. data/lib/outhad/integrations/source/databricks/config/spec.json +56 -0
  183. data/lib/outhad/integrations/source/databricks/icon.svg +19 -0
  184. data/lib/outhad/integrations/source/databrics_model/client.rb +89 -0
  185. data/lib/outhad/integrations/source/databrics_model/config/catalog.json +6 -0
  186. data/lib/outhad/integrations/source/databrics_model/config/meta.json +17 -0
  187. data/lib/outhad/integrations/source/databrics_model/config/spec.json +63 -0
  188. data/lib/outhad/integrations/source/databrics_model/icon.svg +19 -0
  189. data/lib/outhad/integrations/source/firecrawl/client.rb +151 -0
  190. data/lib/outhad/integrations/source/firecrawl/config/catalog.json +29 -0
  191. data/lib/outhad/integrations/source/firecrawl/config/meta.json +17 -0
  192. data/lib/outhad/integrations/source/firecrawl/config/spec.json +31 -0
  193. data/lib/outhad/integrations/source/firecrawl/icon.svg +4 -0
  194. data/lib/outhad/integrations/source/generic_open_ai/client.rb +118 -0
  195. data/lib/outhad/integrations/source/generic_open_ai/config/catalog.json +6 -0
  196. data/lib/outhad/integrations/source/generic_open_ai/config/meta.json +16 -0
  197. data/lib/outhad/integrations/source/generic_open_ai/config/spec.json +63 -0
  198. data/lib/outhad/integrations/source/generic_open_ai/icon.svg +6 -0
  199. data/lib/outhad/integrations/source/google_vertex_model/client.rb +83 -0
  200. data/lib/outhad/integrations/source/google_vertex_model/config/catalog.json +6 -0
  201. data/lib/outhad/integrations/source/google_vertex_model/config/meta.json +17 -0
  202. data/lib/outhad/integrations/source/google_vertex_model/config/spec.json +105 -0
  203. data/lib/outhad/integrations/source/google_vertex_model/icon.svg +2 -0
  204. data/lib/outhad/integrations/source/http_model/client.rb +108 -0
  205. data/lib/outhad/integrations/source/http_model/config/catalog.json +6 -0
  206. data/lib/outhad/integrations/source/http_model/config/meta.json +16 -0
  207. data/lib/outhad/integrations/source/http_model/config/spec.json +70 -0
  208. data/lib/outhad/integrations/source/http_model/icon.svg +9 -0
  209. data/lib/outhad/integrations/source/intuit_quick_books/client.rb +213 -0
  210. data/lib/outhad/integrations/source/intuit_quick_books/config/catalog.json +6 -0
  211. data/lib/outhad/integrations/source/intuit_quick_books/config/meta.json +17 -0
  212. data/lib/outhad/integrations/source/intuit_quick_books/config/spec.json +44 -0
  213. data/lib/outhad/integrations/source/intuit_quick_books/icon.svg +1 -0
  214. data/lib/outhad/integrations/source/maria_db/client.rb +92 -0
  215. data/lib/outhad/integrations/source/maria_db/config/meta.json +16 -0
  216. data/lib/outhad/integrations/source/maria_db/config/spec.json +48 -0
  217. data/lib/outhad/integrations/source/maria_db/icon.svg +15 -0
  218. data/lib/outhad/integrations/source/odoo/client.rb +106 -0
  219. data/lib/outhad/integrations/source/odoo/config/meta.json +15 -0
  220. data/lib/outhad/integrations/source/odoo/config/spec.json +39 -0
  221. data/lib/outhad/integrations/source/odoo/icon.svg +21 -0
  222. data/lib/outhad/integrations/source/open_ai/client.rb +118 -0
  223. data/lib/outhad/integrations/source/open_ai/config/catalog.json +6 -0
  224. data/lib/outhad/integrations/source/open_ai/config/meta.json +16 -0
  225. data/lib/outhad/integrations/source/open_ai/config/spec.json +56 -0
  226. data/lib/outhad/integrations/source/open_ai/icon.svg +1 -0
  227. data/lib/outhad/integrations/source/oracle_db/client.rb +127 -0
  228. data/lib/outhad/integrations/source/oracle_db/config/meta.json +16 -0
  229. data/lib/outhad/integrations/source/oracle_db/config/spec.json +47 -0
  230. data/lib/outhad/integrations/source/oracle_db/icon.svg +4 -0
  231. data/lib/outhad/integrations/source/pinecone_db/client.rb +73 -0
  232. data/lib/outhad/integrations/source/pinecone_db/config/catalog.json +6 -0
  233. data/lib/outhad/integrations/source/pinecone_db/config/meta.json +16 -0
  234. data/lib/outhad/integrations/source/pinecone_db/config/spec.json +34 -0
  235. data/lib/outhad/integrations/source/pinecone_db/icon.svg +2 -0
  236. data/lib/outhad/integrations/source/postgresql/client.rb +112 -0
  237. data/lib/outhad/integrations/source/postgresql/config/meta.json +16 -0
  238. data/lib/outhad/integrations/source/postgresql/config/spec.json +86 -0
  239. data/lib/outhad/integrations/source/postgresql/icon.svg +20 -0
  240. data/lib/outhad/integrations/source/qdrant/client.rb +86 -0
  241. data/lib/outhad/integrations/source/qdrant/config/catalog.json +6 -0
  242. data/lib/outhad/integrations/source/qdrant/config/meta.json +16 -0
  243. data/lib/outhad/integrations/source/qdrant/config/spec.json +29 -0
  244. data/lib/outhad/integrations/source/qdrant/icon.svg +1 -0
  245. data/lib/outhad/integrations/source/redshift/client.rb +109 -0
  246. data/lib/outhad/integrations/source/redshift/config/meta.json +16 -0
  247. data/lib/outhad/integrations/source/redshift/config/spec.json +71 -0
  248. data/lib/outhad/integrations/source/redshift/icon.svg +15 -0
  249. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/client.rb +133 -0
  250. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/config/catalog.json +6 -0
  251. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/config/meta.json +18 -0
  252. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/config/spec.json +53 -0
  253. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/icon.svg +16 -0
  254. data/lib/outhad/integrations/source/salesforce_consumer_goods_cloud/schema_helper.rb +130 -0
  255. data/lib/outhad/integrations/source/sftp/client.rb +133 -0
  256. data/lib/outhad/integrations/source/sftp/config/meta.json +16 -0
  257. data/lib/outhad/integrations/source/sftp/config/spec.json +59 -0
  258. data/lib/outhad/integrations/source/sftp/icon.svg +1 -0
  259. data/lib/outhad/integrations/source/snowflake/client.rb +92 -0
  260. data/lib/outhad/integrations/source/snowflake/config/meta.json +16 -0
  261. data/lib/outhad/integrations/source/snowflake/config/spec.json +82 -0
  262. data/lib/outhad/integrations/source/snowflake/icon.svg +10 -0
  263. data/lib/outhad/integrations/source/watsonx_ai/client.rb +194 -0
  264. data/lib/outhad/integrations/source/watsonx_ai/config/catalog.json +6 -0
  265. data/lib/outhad/integrations/source/watsonx_ai/config/meta.json +16 -0
  266. data/lib/outhad/integrations/source/watsonx_ai/config/spec.json +74 -0
  267. data/lib/outhad/integrations/source/watsonx_ai/icon.svg +1 -0
  268. data/lib/outhad/integrations/source/watsonx_data/client.rb +146 -0
  269. data/lib/outhad/integrations/source/watsonx_data/config/meta.json +17 -0
  270. data/lib/outhad/integrations/source/watsonx_data/config/spec.json +72 -0
  271. data/lib/outhad/integrations/source/watsonx_data/icon.svg +1 -0
  272. data/lib/outhad/integrations.rb +129 -0
  273. data/outhad-integrations.gemspec +79 -0
  274. data/sig/outhad/integrations.rbs +6 -0
  275. metadata +866 -0
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outhad
4
+ module Integrations::Protocol
5
+ module Types
6
+ include Dry.Types()
7
+ end
8
+
9
+ SyncMode = Types::String.enum("full_refresh", "incremental")
10
+ SyncStatus = Types::String.enum("started", "running", "complete", "incomplete")
11
+ DestinationSyncMode = Types::String.enum("insert", "upsert")
12
+ ConnectorType = Types::String.enum("source", "destination")
13
+ ConnectorQueryType = Types::String.enum("raw_sql", "soql", "ai_ml", "vector_search")
14
+ ModelQueryType = Types::String.enum("raw_sql", "dbt", "soql", "table_selector", "ai_ml", "dynamic_sql", "unstructured", "vector_search")
15
+ ConnectionStatusType = Types::String.enum("succeeded", "failed")
16
+ StreamType = Types::String.enum("static", "dynamic", "user_defined")
17
+ StreamAction = Types::String.enum("fetch", "create", "update", "delete")
18
+ OuthadMessageType = Types::String.enum(
19
+ "record", "log", "connector_spec",
20
+ "connection_status", "catalog", "control",
21
+ "tracking"
22
+ )
23
+ ControlMessageType = Types::String.enum(
24
+ "rate_limit", "connection_config", "full_refresh"
25
+ )
26
+ LogLevel = Types::String.enum("fatal", "error", "warn", "info", "debug", "trace")
27
+ RequestRateLimitingUnit = Types::String.default("minute").enum("minute", "hour", "day")
28
+ SchemaMode = Types::String.enum("schema", "schemaless")
29
+ FileFormatType = Types::String.enum("csv")
30
+ CompressionType = Types::String.enum("un_compressed", "zip")
31
+
32
+ class ProtocolModel < Dry::Struct
33
+ extend Outhad::Integrations::Core::Utils
34
+ class << self
35
+ def from_json(json_string)
36
+ data = JSON.parse(json_string)
37
+ new(keys_to_symbols(data))
38
+ end
39
+ end
40
+ end
41
+
42
+ class ConnectionStatus < ProtocolModel
43
+ attribute :status, ConnectionStatusType
44
+ attribute? :message, Types::String.optional
45
+
46
+ def to_outhad_message
47
+ OuthadMessage.new(
48
+ type: OuthadMessageType["connection_status"],
49
+ connection_status: self
50
+ )
51
+ end
52
+ end
53
+
54
+ class ConnectorSpecification < ProtocolModel
55
+ attribute? :documentation_url, Types::String.optional
56
+ attribute? :changelog_url, Types::String.optional
57
+ attribute :connection_specification, Types::Hash
58
+ attribute :supports_normalization, Types::Bool.default(false)
59
+ attribute :supports_dbt, Types::Bool.default(false)
60
+ attribute :stream_type, StreamType
61
+ attribute? :supported_destination_sync_modes, Types::Array.of(DestinationSyncMode).optional
62
+ attribute? :connector_query_type, ConnectorQueryType
63
+
64
+ def to_outhad_message
65
+ OuthadMessage.new(
66
+ type: OuthadMessageType["connector_spec"],
67
+ connector_spec: self
68
+ )
69
+ end
70
+ end
71
+
72
+ class Connector < ProtocolModel
73
+ attribute :name, Types::String
74
+ attribute :type, ConnectorType
75
+ attribute :connection_specification, Types::Hash
76
+ attribute :connector_instance, Types::Any.optional.default(nil)
77
+ attribute :query_type, Types::String.default("raw_sql").enum(*ConnectorQueryType.values)
78
+ end
79
+
80
+ class LogMessage < ProtocolModel
81
+ attribute :level, LogLevel
82
+ attribute :message, Types::String
83
+ attribute? :name, Types::String.optional
84
+ attribute? :stack_trace, Types::String.optional
85
+
86
+ def to_outhad_message
87
+ OuthadMessage.new(
88
+ type: OuthadMessageType["log"],
89
+ log: self
90
+ )
91
+ end
92
+ end
93
+
94
+ class Model < ProtocolModel
95
+ attribute? :name, Types::String.optional
96
+ attribute :query, Types::String
97
+ attribute :query_type, ModelQueryType
98
+ attribute :primary_key, Types::String
99
+ end
100
+
101
+ class RecordMessage < ProtocolModel
102
+ attribute :data, Types::Hash
103
+ attribute :emitted_at, Types::Integer
104
+
105
+ def to_outhad_message
106
+ OuthadMessage.new(
107
+ type: OuthadMessageType["record"],
108
+ record: self
109
+ )
110
+ end
111
+ end
112
+
113
+ class Stream < ProtocolModel
114
+ # Common
115
+ attribute :name, Types::String
116
+ attribute? :action, StreamAction
117
+ attribute :json_schema, Types::Hash
118
+ attribute? :supported_sync_modes, Types::Array.of(SyncMode).optional.default(["incremental"])
119
+
120
+ # Applicable for database streams
121
+ attribute :source_defined_cursor, Types::Bool.default(false)
122
+ attribute? :default_cursor_field, Types::Array.of(Types::String).optional
123
+ attribute? :source_defined_primary_key, Types::Array.of(Types::Array.of(Types::String)).optional
124
+ attribute? :namespace, Types::String.optional
125
+ # Applicable for API streams
126
+ attribute? :url, Types::String.optional
127
+ attribute? :request_method, Types::String.optional
128
+ attribute :batch_support, Types::Bool.default(false)
129
+ attribute :batch_size, Types::Integer.default(1)
130
+ # Rate limits
131
+ attribute? :request_rate_limit, Types::Integer
132
+ attribute? :request_rate_limit_unit, RequestRateLimitingUnit
133
+ attribute? :request_rate_concurrency, Types::Integer
134
+
135
+ def rate_limit_unit_seconds
136
+ case request_rate_limit_unit
137
+ when "minute"
138
+ 60 # Seconds in a minute
139
+ when "hour"
140
+ 3600 # Seconds in an hour
141
+ when "day"
142
+ 86_400 # Seconds in a day
143
+ else
144
+ 1 # Default case, consider as seconds or handle as error
145
+ end
146
+ end
147
+ end
148
+
149
+ class Catalog < ProtocolModel
150
+ attribute :streams, Types::Array.of(Stream)
151
+
152
+ # Rate limits
153
+ attribute? :request_rate_limit, Types::Integer.default(60)
154
+ attribute? :request_rate_limit_unit, RequestRateLimitingUnit
155
+ attribute? :request_rate_concurrency, Types::Integer.default(10)
156
+ attribute? :schema_mode, Types::String.optional.default("schema")
157
+ attribute :source_defined_cursor, Types::Bool.default(false)
158
+ attribute? :default_cursor_field, Types::Array.of(Types::String).optional
159
+
160
+ def to_outhad_message
161
+ OuthadMessage.new(
162
+ type: OuthadMessageType["catalog"],
163
+ catalog: self
164
+ )
165
+ end
166
+ end
167
+
168
+ class SyncConfig < ProtocolModel
169
+ attr_accessor :offset, :limit, :sync_run_id
170
+
171
+ attribute :source, Connector
172
+ attribute :destination, Connector
173
+ attribute :model, Model
174
+ attribute :stream, Stream
175
+ attribute :sync_mode, SyncMode
176
+ attribute? :cursor_field, Types::String.optional
177
+ attribute? :current_cursor_field, Types::String.optional
178
+ attribute :destination_sync_mode, DestinationSyncMode
179
+ # reference ids
180
+ attribute :sync_id, Types::String.default("unknown")
181
+ end
182
+
183
+ class VectorConfig < ProtocolModel
184
+ attribute :source, Connector
185
+ attribute :vector, Types::Array.of(Types::Float)
186
+ attribute :limit, Types::Integer.default(1)
187
+ end
188
+
189
+ class ControlMessage < ProtocolModel
190
+ attribute :type, ControlMessageType
191
+ attribute :emitted_at, Types::Integer
192
+ attribute? :status, ConnectionStatusType.optional
193
+ attribute? :meta, Types::Hash
194
+
195
+ def to_outhad_message
196
+ OuthadMessage.new(
197
+ type: OuthadMessageType["control"],
198
+ control: self
199
+ )
200
+ end
201
+ end
202
+
203
+ class TrackingMessage < ProtocolModel
204
+ attribute :success, Types::Integer.default(0)
205
+ attribute :failed, Types::Integer.default(0)
206
+ attribute? :meta, Types::Hash
207
+ attribute? :logs, Types::Array.of(LogMessage)
208
+
209
+ def to_outhad_message
210
+ OuthadMessage.new(
211
+ type: OuthadMessageType["tracking"],
212
+ tracking: self
213
+ )
214
+ end
215
+ end
216
+
217
+ class OuthadMessage < ProtocolModel
218
+ attribute :type, OuthadMessageType
219
+ attribute? :log, LogMessage.optional
220
+ attribute? :connection_status, ConnectionStatus.optional
221
+ attribute? :connector_spec, ConnectorSpecification.optional
222
+ attribute? :catalog, Catalog.optional
223
+ attribute? :record, RecordMessage.optional
224
+ attribute? :control, ControlMessage.optional
225
+ attribute? :tracking, TrackingMessage.optional
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outhad
4
+ module Integrations
5
+ VERSION = "0.32.0"
6
+
7
+ ENABLED_SOURCES = %w[
8
+ Snowflake
9
+ Redshift
10
+ Bigquery
11
+ Postgresql
12
+ Databricks
13
+ SalesforceConsumerGoodsCloud
14
+ AwsAthena
15
+ Clickhouse
16
+ AmazonS3
17
+ MariaDB
18
+ Oracle
19
+ DatabricksModel
20
+ AwsSagemakerModel
21
+ VertexModel
22
+ HttpModel
23
+ OpenAI
24
+ Sftp
25
+ WatsonxAi
26
+ WatsonxData
27
+ Anthropic
28
+ AwsBedrockModel
29
+ GenericOpenAI
30
+ IntuitQuickBooks
31
+ PineconeDB
32
+ Qdrant
33
+ Firecrawl
34
+ Odoo
35
+ ].freeze
36
+
37
+ ENABLED_DESTINATIONS = %w[
38
+ Klaviyo
39
+ SalesforceCrm
40
+ FacebookCustomAudience
41
+ Slack
42
+ Hubspot
43
+ GoogleSheets
44
+ Airtable
45
+ Stripe
46
+ SalesforceConsumerGoodsCloud
47
+ Sftp
48
+ Postgresql
49
+ Zendesk
50
+ Http
51
+ Iterable
52
+ MariaDB
53
+ DatabricksLakehouse
54
+ Oracle
55
+ MicrosoftExcel
56
+ MicrosoftSql
57
+ Mailchimp
58
+ AISDataStore
59
+ AmazonS3
60
+ MicrosoftDynamics
61
+ Qdrant
62
+ PineconeDB
63
+ Odoo
64
+ ].freeze
65
+ end
66
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outhad
4
+ module Integrations
5
+ class Service
6
+ def initialize
7
+ yield(self.class.config) if block_given?
8
+ end
9
+ class << self
10
+ def connectors
11
+ {
12
+ source: build_connectors(
13
+ ENABLED_SOURCES, "Source"
14
+ ),
15
+ destination: build_connectors(
16
+ ENABLED_DESTINATIONS, "Destination"
17
+ )
18
+ }
19
+ end
20
+
21
+ def connector_class(connector_type, connector_name)
22
+ Object.const_get(
23
+ "Outhad::Integrations::#{connector_type}::#{connector_name}::Client"
24
+ )
25
+ end
26
+
27
+ def logger
28
+ config.logger || default_logger
29
+ end
30
+
31
+ def exception_reporter
32
+ config.exception_reporter
33
+ end
34
+
35
+ def config
36
+ @config ||= Config.new
37
+ end
38
+
39
+ private
40
+
41
+ def build_connectors(enabled_connectors, type)
42
+ enabled_connectors.map do |connector|
43
+ client = connector_class(type, connector).new
44
+ client.meta_data[:data][:connector_spec] = client.connector_spec.to_h
45
+ client.meta_data[:data]
46
+ end
47
+ end
48
+
49
+ def default_logger
50
+ @default_logger ||= Logger.new($stdout)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,235 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outhad::Integrations::Source
4
+ module AmazonS3
5
+ include Outhad::Integrations::Core
6
+ class Client < UnstructuredSourceConnector
7
+ @session_name = ""
8
+
9
+ def check_connection(connection_config)
10
+ connection_config = connection_config.with_indifferent_access
11
+ @session_name = "connection-#{connection_config[:region]}-#{connection_config[:bucket]}"
12
+
13
+ if unstructured_data?(connection_config)
14
+ create_s3_connection(connection_config)
15
+ @s3_resource.bucket(connection_config[:bucket]).objects.limit(1).first
16
+ else
17
+ conn = create_connection(connection_config)
18
+ path = build_path(connection_config)
19
+ get_results(conn, "DESCRIBE SELECT * FROM '#{path}';")
20
+ end
21
+ ConnectionStatus.new(status: ConnectionStatusType["succeeded"]).to_outhad_message
22
+ rescue StandardError => e
23
+ ConnectionStatus.new(status: ConnectionStatusType["failed"], message: e.message).to_outhad_message
24
+ end
25
+
26
+ def discover(connection_config)
27
+ connection_config = connection_config.with_indifferent_access
28
+ @session_name = "discover-#{connection_config[:region]}-#{connection_config[:bucket]}"
29
+
30
+ streams = if unstructured_data?(connection_config)
31
+ [create_unstructured_stream]
32
+ else
33
+ conn = create_connection(connection_config)
34
+ # If pulling from multiple files, all files must have the same schema
35
+ path = build_path(connection_config)
36
+ records = get_results(conn, "DESCRIBE SELECT * FROM '#{path}';")
37
+ columns = build_discover_columns(records)
38
+ [Outhad::Integrations::Protocol::Stream.new(name: path, action: StreamAction["fetch"], json_schema: convert_to_json_schema(columns))]
39
+ end
40
+ catalog = Catalog.new(streams: streams)
41
+ catalog.to_outhad_message
42
+ rescue StandardError => e
43
+ handle_exception(e, { context: "AMAZONS3:DISCOVER:EXCEPTION", type: "error" })
44
+ end
45
+
46
+ def read(sync_config)
47
+ connection_config = sync_config.source.connection_specification.with_indifferent_access
48
+ @session_name = "#{sync_config.sync_id}-#{sync_config.source.name}-#{sync_config.destination.name}"
49
+
50
+ return handle_unstructured_data(sync_config) if unstructured_data?(connection_config)
51
+
52
+ conn = create_connection(connection_config)
53
+ query = sync_config.model.query
54
+ query = batched_query(query, sync_config.limit, sync_config.offset) unless sync_config.limit.nil? && sync_config.offset.nil?
55
+ query(conn, query)
56
+ rescue StandardError => e
57
+ handle_exception(e, {
58
+ context: "AMAZONS3:READ:EXCEPTION",
59
+ type: "error",
60
+ sync_id: sync_config.sync_id,
61
+ sync_run_id: sync_config.sync_run_id
62
+ })
63
+ end
64
+
65
+ private
66
+
67
+ def get_auth_data(connection_config)
68
+ session = @session_name.gsub(/\s+/, "-")
69
+ @session_name = ""
70
+ if connection_config[:auth_type] == "user"
71
+ Aws::Credentials.new(connection_config[:access_id], connection_config[:secret_access])
72
+ elsif connection_config[:auth_type] == "role"
73
+ sts_client = Aws::STS::Client.new(region: connection_config[:region])
74
+ resp = sts_client.assume_role({
75
+ role_arn: connection_config[:arn],
76
+ role_session_name: session,
77
+ external_id: connection_config[:external_id]
78
+ })
79
+ Aws::Credentials.new(
80
+ resp.credentials.access_key_id,
81
+ resp.credentials.secret_access_key,
82
+ resp.credentials.session_token
83
+ )
84
+ end
85
+ end
86
+
87
+ def create_s3_connection(connection_config)
88
+ connection_config = connection_config.with_indifferent_access
89
+
90
+ # Get authentication credentials
91
+ auth_data = get_auth_data(connection_config)
92
+
93
+ # Create S3 resource for easier operations
94
+ @s3_resource = Aws::S3::Resource.new(
95
+ region: connection_config[:region],
96
+ credentials: auth_data
97
+ )
98
+ end
99
+
100
+ def create_connection(connection_config)
101
+ # In the case when previewing a query
102
+ @session_name = "preview-#{connection_config[:region]}-#{connection_config[:bucket]}" if @session_name.to_s.empty?
103
+ auth_data = get_auth_data(connection_config)
104
+ conn = DuckDB::Database.open.connect
105
+ # Install and/or Load the HTTPFS extension
106
+ conn.execute(INSTALL_HTTPFS_QUERY)
107
+ # Set up S3 configuration
108
+ secret_query = "
109
+ CREATE SECRET amazons3_source (
110
+ TYPE S3,
111
+ KEY_ID '#{auth_data.credentials.access_key_id}',
112
+ SECRET '#{auth_data.credentials.secret_access_key}',
113
+ REGION '#{connection_config[:region]}',
114
+ SESSION_TOKEN '#{auth_data.credentials.session_token}'
115
+ );
116
+ "
117
+ get_results(conn, secret_query)
118
+ conn
119
+ end
120
+
121
+ def build_path(connection_config)
122
+ path = connection_config[:path]
123
+ path = "#{path}/" if path.to_s.strip.empty? || path[-1] != "/"
124
+ "s3://#{connection_config[:bucket]}#{path}*.#{connection_config[:file_type]}"
125
+ end
126
+
127
+ def get_results(conn, query)
128
+ results = conn.query(query)
129
+ hash_array_values(results)
130
+ end
131
+
132
+ def query(conn, query)
133
+ records = get_results(conn, query)
134
+ records.map do |row|
135
+ RecordMessage.new(data: row, emitted_at: Time.now.to_i).to_outhad_message
136
+ end
137
+ end
138
+
139
+ def hash_array_values(describe)
140
+ keys = describe.columns.map(&:name)
141
+ describe.map do |row|
142
+ Hash[keys.zip(row)]
143
+ end
144
+ end
145
+
146
+ def build_discover_columns(describe_results)
147
+ describe_results.map do |row|
148
+ type = column_schema_helper(row["column_type"])
149
+ {
150
+ column_name: row["column_name"],
151
+ type: type
152
+ }
153
+ end
154
+ end
155
+
156
+ def column_schema_helper(column_type)
157
+ case column_type
158
+ when "VARCHAR", "BIT", "DATE", "TIME", "TIMESTAMP", "UUID"
159
+ "string"
160
+ when "DOUBLE"
161
+ "number"
162
+ when "BIGINT", "HUGEINT", "INTEGER", "SMALLINT"
163
+ "integer"
164
+ when "BOOLEAN"
165
+ "boolean"
166
+ end
167
+ end
168
+
169
+ def handle_unstructured_data(sync_config)
170
+ connection_config = sync_config.source.connection_specification.with_indifferent_access
171
+ bucket_name = connection_config[:bucket]
172
+ command = sync_config.model.query.strip
173
+ create_s3_connection(connection_config)
174
+
175
+ case command
176
+ when LIST_FILES_CMD
177
+ list_files_in_folder(bucket_name, connection_config[:path] || "")
178
+ when /^#{DOWNLOAD_FILE_CMD}\s+(.+)$/
179
+ # Extract the file path and remove surrounding quotes if present
180
+ file_path = ::Regexp.last_match(1).strip
181
+ file_path = file_path.gsub(/^["']|["']$/, "") # Remove leading/trailing quotes
182
+ download_file_to_local(bucket_name, file_path, sync_config.sync_id)
183
+ else
184
+ raise "Invalid command. Supported commands: #{LIST_FILES_CMD}, #{DOWNLOAD_FILE_CMD} <file_path>"
185
+ end
186
+ end
187
+
188
+ def list_files_in_folder(bucket_name, folder_path)
189
+ folder_path = folder_path.end_with?("/") ? folder_path : "#{folder_path}/"
190
+ bucket = @s3_resource.bucket(bucket_name)
191
+
192
+ bucket.objects(prefix: folder_path).reject { |object| object.key == folder_path }.map do |object|
193
+ RecordMessage.new(
194
+ data: {
195
+ file_name: File.basename(object.key),
196
+ file_path: object.key,
197
+ size: object.content_length,
198
+ file_type: File.extname(object.key).sub(".", ""),
199
+ created_date: object.last_modified.to_s,
200
+ modified_date: object.last_modified.to_s
201
+ },
202
+ emitted_at: Time.now.to_i
203
+ ).to_outhad_message
204
+ end
205
+ end
206
+
207
+ def download_file_to_local(bucket_name, file_path, sync_id)
208
+ download_path = ENV["FILE_DOWNLOAD_PATH"]
209
+ file = if download_path
210
+ File.join(download_path, "syncs", sync_id, File.basename(file_path))
211
+ else
212
+ Tempfile.new(["s3_file", "syncs", sync_id, File.extname(file_path)]).path
213
+ end
214
+
215
+ object = @s3_resource.bucket(bucket_name).object(file_path)
216
+ object.get(response_target: file)
217
+
218
+ [RecordMessage.new(
219
+ data: {
220
+ local_path: file,
221
+ file_name: File.basename(file_path),
222
+ file_path: file_path,
223
+ size: object.content_length,
224
+ file_type: File.extname(file_path).sub(".", ""),
225
+ modified_date: object.last_modified.to_s,
226
+ created_date: object.last_modified.to_s
227
+ },
228
+ emitted_at: Time.now.to_i
229
+ ).to_outhad_message]
230
+ rescue Aws::S3::Errors::NoSuchKey
231
+ raise "File not found: #{file_path}"
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,16 @@
1
+ {
2
+ "data": {
3
+ "name": "AmazonS3",
4
+ "title": "Amazon S3",
5
+ "connector_type": "source",
6
+ "category": "Data Lake",
7
+ "sub_category": "Relational Database",
8
+ "documentation_url": "https://docs.squared.ai/guides/sources/data-sources/amazon_s3",
9
+ "github_issue_label": "source-amazons3",
10
+ "icon": "icon.svg",
11
+ "license": "MIT",
12
+ "release_stage": "alpha",
13
+ "support_level": "community",
14
+ "tags": ["language:ruby", "outhad"]
15
+ }
16
+ }