recurvedata-lib 0.1.487__py2.py3-none-any.whl

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 recurvedata-lib might be problematic. Click here for more details.

Files changed (333) hide show
  1. recurvedata/__init__.py +0 -0
  2. recurvedata/__version__.py +1 -0
  3. recurvedata/client/__init__.py +3 -0
  4. recurvedata/client/client.py +150 -0
  5. recurvedata/client/server_client.py +91 -0
  6. recurvedata/config.py +99 -0
  7. recurvedata/connectors/__init__.py +20 -0
  8. recurvedata/connectors/_register.py +46 -0
  9. recurvedata/connectors/base.py +111 -0
  10. recurvedata/connectors/config_schema.py +1575 -0
  11. recurvedata/connectors/connectors/__init__.py +0 -0
  12. recurvedata/connectors/connectors/aliyun_access_key.py +30 -0
  13. recurvedata/connectors/connectors/auth.py +44 -0
  14. recurvedata/connectors/connectors/azure_blob.py +89 -0
  15. recurvedata/connectors/connectors/azure_synapse.py +79 -0
  16. recurvedata/connectors/connectors/bigquery.py +359 -0
  17. recurvedata/connectors/connectors/clickhouse.py +219 -0
  18. recurvedata/connectors/connectors/dingtalk.py +61 -0
  19. recurvedata/connectors/connectors/doris.py +215 -0
  20. recurvedata/connectors/connectors/es.py +62 -0
  21. recurvedata/connectors/connectors/feishu.py +65 -0
  22. recurvedata/connectors/connectors/ftp.py +50 -0
  23. recurvedata/connectors/connectors/generic.py +49 -0
  24. recurvedata/connectors/connectors/google_cloud_storage.py +115 -0
  25. recurvedata/connectors/connectors/google_service_account.py +225 -0
  26. recurvedata/connectors/connectors/hive.py +207 -0
  27. recurvedata/connectors/connectors/impala.py +210 -0
  28. recurvedata/connectors/connectors/jenkins.py +51 -0
  29. recurvedata/connectors/connectors/mail.py +89 -0
  30. recurvedata/connectors/connectors/microsoft_fabric.py +284 -0
  31. recurvedata/connectors/connectors/mongo.py +79 -0
  32. recurvedata/connectors/connectors/mssql.py +131 -0
  33. recurvedata/connectors/connectors/mysql.py +191 -0
  34. recurvedata/connectors/connectors/n8n.py +141 -0
  35. recurvedata/connectors/connectors/oss.py +74 -0
  36. recurvedata/connectors/connectors/owncloud.py +36 -0
  37. recurvedata/connectors/connectors/phoenix.py +36 -0
  38. recurvedata/connectors/connectors/postgres.py +230 -0
  39. recurvedata/connectors/connectors/python.py +50 -0
  40. recurvedata/connectors/connectors/redshift.py +187 -0
  41. recurvedata/connectors/connectors/s3.py +93 -0
  42. recurvedata/connectors/connectors/sftp.py +87 -0
  43. recurvedata/connectors/connectors/slack.py +35 -0
  44. recurvedata/connectors/connectors/spark.py +99 -0
  45. recurvedata/connectors/connectors/starrocks.py +175 -0
  46. recurvedata/connectors/connectors/tencent_cos.py +40 -0
  47. recurvedata/connectors/connectors/tidb.py +49 -0
  48. recurvedata/connectors/const.py +315 -0
  49. recurvedata/connectors/datasource.py +189 -0
  50. recurvedata/connectors/dbapi.py +469 -0
  51. recurvedata/connectors/fs.py +66 -0
  52. recurvedata/connectors/ftp.py +40 -0
  53. recurvedata/connectors/object_store.py +60 -0
  54. recurvedata/connectors/pigeon.py +172 -0
  55. recurvedata/connectors/proxy.py +104 -0
  56. recurvedata/connectors/service.py +223 -0
  57. recurvedata/connectors/utils.py +47 -0
  58. recurvedata/consts.py +49 -0
  59. recurvedata/core/__init__.py +0 -0
  60. recurvedata/core/config.py +46 -0
  61. recurvedata/core/configurable.py +27 -0
  62. recurvedata/core/consts.py +2 -0
  63. recurvedata/core/templating.py +206 -0
  64. recurvedata/core/tracing.py +223 -0
  65. recurvedata/core/transformer.py +186 -0
  66. recurvedata/core/translation.py +91 -0
  67. recurvedata/dbt/client.py +97 -0
  68. recurvedata/dbt/consts.py +99 -0
  69. recurvedata/dbt/cosmos_utils.py +275 -0
  70. recurvedata/dbt/error_codes.py +18 -0
  71. recurvedata/dbt/schemas.py +98 -0
  72. recurvedata/dbt/service.py +451 -0
  73. recurvedata/dbt/utils.py +246 -0
  74. recurvedata/error_codes.py +71 -0
  75. recurvedata/exceptions.py +72 -0
  76. recurvedata/executors/__init__.py +4 -0
  77. recurvedata/executors/cli/__init__.py +7 -0
  78. recurvedata/executors/cli/connector.py +117 -0
  79. recurvedata/executors/cli/dbt.py +118 -0
  80. recurvedata/executors/cli/main.py +82 -0
  81. recurvedata/executors/cli/parameters.py +18 -0
  82. recurvedata/executors/client.py +190 -0
  83. recurvedata/executors/consts.py +50 -0
  84. recurvedata/executors/debug_executor.py +100 -0
  85. recurvedata/executors/executor.py +300 -0
  86. recurvedata/executors/link_executor.py +189 -0
  87. recurvedata/executors/models.py +34 -0
  88. recurvedata/executors/schemas.py +222 -0
  89. recurvedata/executors/service/__init__.py +0 -0
  90. recurvedata/executors/service/connector.py +380 -0
  91. recurvedata/executors/utils.py +172 -0
  92. recurvedata/filestorage/__init__.py +11 -0
  93. recurvedata/filestorage/_factory.py +33 -0
  94. recurvedata/filestorage/backends/__init__.py +0 -0
  95. recurvedata/filestorage/backends/fsspec.py +45 -0
  96. recurvedata/filestorage/backends/local.py +67 -0
  97. recurvedata/filestorage/backends/oss.py +56 -0
  98. recurvedata/filestorage/interface.py +84 -0
  99. recurvedata/operators/__init__.py +10 -0
  100. recurvedata/operators/base.py +28 -0
  101. recurvedata/operators/config.py +21 -0
  102. recurvedata/operators/context.py +255 -0
  103. recurvedata/operators/dbt_operator/__init__.py +2 -0
  104. recurvedata/operators/dbt_operator/model_pipeline_link_operator.py +55 -0
  105. recurvedata/operators/dbt_operator/operator.py +353 -0
  106. recurvedata/operators/link_operator/__init__.py +1 -0
  107. recurvedata/operators/link_operator/operator.py +120 -0
  108. recurvedata/operators/models.py +55 -0
  109. recurvedata/operators/notify_operator/__init__.py +1 -0
  110. recurvedata/operators/notify_operator/operator.py +180 -0
  111. recurvedata/operators/operator.py +119 -0
  112. recurvedata/operators/python_operator/__init__.py +1 -0
  113. recurvedata/operators/python_operator/operator.py +132 -0
  114. recurvedata/operators/sensor_operator/__init__.py +1 -0
  115. recurvedata/operators/sensor_operator/airflow_utils.py +63 -0
  116. recurvedata/operators/sensor_operator/operator.py +172 -0
  117. recurvedata/operators/spark_operator/__init__.py +1 -0
  118. recurvedata/operators/spark_operator/operator.py +200 -0
  119. recurvedata/operators/spark_operator/spark_sample.py +47 -0
  120. recurvedata/operators/sql_operator/__init__.py +1 -0
  121. recurvedata/operators/sql_operator/operator.py +90 -0
  122. recurvedata/operators/task.py +211 -0
  123. recurvedata/operators/transfer_operator/__init__.py +40 -0
  124. recurvedata/operators/transfer_operator/const.py +10 -0
  125. recurvedata/operators/transfer_operator/dump_aliyun_sls.py +82 -0
  126. recurvedata/operators/transfer_operator/dump_sheet_task_base.py +292 -0
  127. recurvedata/operators/transfer_operator/dump_task_cass.py +155 -0
  128. recurvedata/operators/transfer_operator/dump_task_dbapi.py +209 -0
  129. recurvedata/operators/transfer_operator/dump_task_es.py +113 -0
  130. recurvedata/operators/transfer_operator/dump_task_feishu_sheet.py +114 -0
  131. recurvedata/operators/transfer_operator/dump_task_ftp.py +234 -0
  132. recurvedata/operators/transfer_operator/dump_task_google_sheet.py +66 -0
  133. recurvedata/operators/transfer_operator/dump_task_mongodb.py +168 -0
  134. recurvedata/operators/transfer_operator/dump_task_oss.py +285 -0
  135. recurvedata/operators/transfer_operator/dump_task_python.py +212 -0
  136. recurvedata/operators/transfer_operator/dump_task_s3.py +270 -0
  137. recurvedata/operators/transfer_operator/dump_task_sftp.py +229 -0
  138. recurvedata/operators/transfer_operator/load_task_aliyun_oss.py +107 -0
  139. recurvedata/operators/transfer_operator/load_task_azure_blob.py +115 -0
  140. recurvedata/operators/transfer_operator/load_task_azure_synapse.py +90 -0
  141. recurvedata/operators/transfer_operator/load_task_clickhouse.py +167 -0
  142. recurvedata/operators/transfer_operator/load_task_doris.py +164 -0
  143. recurvedata/operators/transfer_operator/load_task_email.py +188 -0
  144. recurvedata/operators/transfer_operator/load_task_es.py +86 -0
  145. recurvedata/operators/transfer_operator/load_task_filebrowser.py +151 -0
  146. recurvedata/operators/transfer_operator/load_task_ftp.py +19 -0
  147. recurvedata/operators/transfer_operator/load_task_google_bigquery.py +90 -0
  148. recurvedata/operators/transfer_operator/load_task_google_cloud_storage.py +127 -0
  149. recurvedata/operators/transfer_operator/load_task_google_sheet.py +130 -0
  150. recurvedata/operators/transfer_operator/load_task_hive.py +158 -0
  151. recurvedata/operators/transfer_operator/load_task_microsoft_fabric.py +105 -0
  152. recurvedata/operators/transfer_operator/load_task_mssql.py +153 -0
  153. recurvedata/operators/transfer_operator/load_task_mysql.py +157 -0
  154. recurvedata/operators/transfer_operator/load_task_owncloud.py +135 -0
  155. recurvedata/operators/transfer_operator/load_task_postgresql.py +109 -0
  156. recurvedata/operators/transfer_operator/load_task_qcloud_cos.py +119 -0
  157. recurvedata/operators/transfer_operator/load_task_recurve_data_prep.py +75 -0
  158. recurvedata/operators/transfer_operator/load_task_redshift.py +95 -0
  159. recurvedata/operators/transfer_operator/load_task_s3.py +150 -0
  160. recurvedata/operators/transfer_operator/load_task_sftp.py +90 -0
  161. recurvedata/operators/transfer_operator/load_task_starrocks.py +169 -0
  162. recurvedata/operators/transfer_operator/load_task_yicrowds.py +97 -0
  163. recurvedata/operators/transfer_operator/mixin.py +31 -0
  164. recurvedata/operators/transfer_operator/operator.py +231 -0
  165. recurvedata/operators/transfer_operator/task.py +223 -0
  166. recurvedata/operators/transfer_operator/utils.py +134 -0
  167. recurvedata/operators/ui.py +80 -0
  168. recurvedata/operators/utils/__init__.py +51 -0
  169. recurvedata/operators/utils/file_factory.py +150 -0
  170. recurvedata/operators/utils/fs.py +10 -0
  171. recurvedata/operators/utils/lineage.py +265 -0
  172. recurvedata/operators/web_init.py +15 -0
  173. recurvedata/pigeon/connector/__init__.py +294 -0
  174. recurvedata/pigeon/connector/_registry.py +17 -0
  175. recurvedata/pigeon/connector/aliyun_oss.py +80 -0
  176. recurvedata/pigeon/connector/awss3.py +123 -0
  177. recurvedata/pigeon/connector/azure_blob.py +176 -0
  178. recurvedata/pigeon/connector/azure_synapse.py +51 -0
  179. recurvedata/pigeon/connector/cass.py +151 -0
  180. recurvedata/pigeon/connector/clickhouse.py +403 -0
  181. recurvedata/pigeon/connector/clickhouse_native.py +351 -0
  182. recurvedata/pigeon/connector/dbapi.py +571 -0
  183. recurvedata/pigeon/connector/doris.py +166 -0
  184. recurvedata/pigeon/connector/es.py +176 -0
  185. recurvedata/pigeon/connector/feishu.py +1135 -0
  186. recurvedata/pigeon/connector/ftp.py +163 -0
  187. recurvedata/pigeon/connector/google_bigquery.py +283 -0
  188. recurvedata/pigeon/connector/google_cloud_storage.py +130 -0
  189. recurvedata/pigeon/connector/hbase_phoenix.py +108 -0
  190. recurvedata/pigeon/connector/hdfs.py +204 -0
  191. recurvedata/pigeon/connector/hive_impala.py +383 -0
  192. recurvedata/pigeon/connector/microsoft_fabric.py +95 -0
  193. recurvedata/pigeon/connector/mongodb.py +56 -0
  194. recurvedata/pigeon/connector/mssql.py +467 -0
  195. recurvedata/pigeon/connector/mysql.py +175 -0
  196. recurvedata/pigeon/connector/owncloud.py +92 -0
  197. recurvedata/pigeon/connector/postgresql.py +267 -0
  198. recurvedata/pigeon/connector/power_bi.py +179 -0
  199. recurvedata/pigeon/connector/qcloud_cos.py +79 -0
  200. recurvedata/pigeon/connector/redshift.py +123 -0
  201. recurvedata/pigeon/connector/sftp.py +73 -0
  202. recurvedata/pigeon/connector/sqlite.py +42 -0
  203. recurvedata/pigeon/connector/starrocks.py +144 -0
  204. recurvedata/pigeon/connector/tableau.py +162 -0
  205. recurvedata/pigeon/const.py +21 -0
  206. recurvedata/pigeon/csv.py +172 -0
  207. recurvedata/pigeon/docs/datasources-example.json +82 -0
  208. recurvedata/pigeon/docs/images/pigeon_design.png +0 -0
  209. recurvedata/pigeon/docs/lightweight-data-sync-solution.md +111 -0
  210. recurvedata/pigeon/dumper/__init__.py +171 -0
  211. recurvedata/pigeon/dumper/aliyun_sls.py +415 -0
  212. recurvedata/pigeon/dumper/base.py +141 -0
  213. recurvedata/pigeon/dumper/cass.py +213 -0
  214. recurvedata/pigeon/dumper/dbapi.py +346 -0
  215. recurvedata/pigeon/dumper/es.py +112 -0
  216. recurvedata/pigeon/dumper/ftp.py +64 -0
  217. recurvedata/pigeon/dumper/mongodb.py +103 -0
  218. recurvedata/pigeon/handler/__init__.py +4 -0
  219. recurvedata/pigeon/handler/base.py +153 -0
  220. recurvedata/pigeon/handler/csv_handler.py +290 -0
  221. recurvedata/pigeon/loader/__init__.py +87 -0
  222. recurvedata/pigeon/loader/base.py +83 -0
  223. recurvedata/pigeon/loader/csv_to_azure_synapse.py +214 -0
  224. recurvedata/pigeon/loader/csv_to_clickhouse.py +152 -0
  225. recurvedata/pigeon/loader/csv_to_doris.py +215 -0
  226. recurvedata/pigeon/loader/csv_to_es.py +51 -0
  227. recurvedata/pigeon/loader/csv_to_google_bigquery.py +169 -0
  228. recurvedata/pigeon/loader/csv_to_hive.py +468 -0
  229. recurvedata/pigeon/loader/csv_to_microsoft_fabric.py +242 -0
  230. recurvedata/pigeon/loader/csv_to_mssql.py +174 -0
  231. recurvedata/pigeon/loader/csv_to_mysql.py +180 -0
  232. recurvedata/pigeon/loader/csv_to_postgresql.py +248 -0
  233. recurvedata/pigeon/loader/csv_to_redshift.py +240 -0
  234. recurvedata/pigeon/loader/csv_to_starrocks.py +233 -0
  235. recurvedata/pigeon/meta.py +116 -0
  236. recurvedata/pigeon/row_factory.py +42 -0
  237. recurvedata/pigeon/schema/__init__.py +124 -0
  238. recurvedata/pigeon/schema/types.py +13 -0
  239. recurvedata/pigeon/sync.py +283 -0
  240. recurvedata/pigeon/transformer.py +146 -0
  241. recurvedata/pigeon/utils/__init__.py +134 -0
  242. recurvedata/pigeon/utils/bloomfilter.py +181 -0
  243. recurvedata/pigeon/utils/date_time.py +323 -0
  244. recurvedata/pigeon/utils/escape.py +15 -0
  245. recurvedata/pigeon/utils/fs.py +266 -0
  246. recurvedata/pigeon/utils/json.py +44 -0
  247. recurvedata/pigeon/utils/keyed_tuple.py +85 -0
  248. recurvedata/pigeon/utils/mp.py +156 -0
  249. recurvedata/pigeon/utils/sql.py +328 -0
  250. recurvedata/pigeon/utils/timing.py +155 -0
  251. recurvedata/provider_manager.py +0 -0
  252. recurvedata/providers/__init__.py +0 -0
  253. recurvedata/providers/dbapi/__init__.py +0 -0
  254. recurvedata/providers/flywheel/__init__.py +0 -0
  255. recurvedata/providers/mysql/__init__.py +0 -0
  256. recurvedata/schedulers/__init__.py +1 -0
  257. recurvedata/schedulers/airflow.py +974 -0
  258. recurvedata/schedulers/airflow_db_process.py +331 -0
  259. recurvedata/schedulers/airflow_operators.py +61 -0
  260. recurvedata/schedulers/airflow_plugin.py +9 -0
  261. recurvedata/schedulers/airflow_trigger_dag_patch.py +117 -0
  262. recurvedata/schedulers/base.py +99 -0
  263. recurvedata/schedulers/cli.py +228 -0
  264. recurvedata/schedulers/client.py +56 -0
  265. recurvedata/schedulers/consts.py +52 -0
  266. recurvedata/schedulers/debug_celery.py +62 -0
  267. recurvedata/schedulers/model.py +63 -0
  268. recurvedata/schedulers/schemas.py +97 -0
  269. recurvedata/schedulers/service.py +20 -0
  270. recurvedata/schedulers/system_dags.py +59 -0
  271. recurvedata/schedulers/task_status.py +279 -0
  272. recurvedata/schedulers/utils.py +73 -0
  273. recurvedata/schema/__init__.py +0 -0
  274. recurvedata/schema/field.py +88 -0
  275. recurvedata/schema/schema.py +55 -0
  276. recurvedata/schema/types.py +17 -0
  277. recurvedata/schema.py +0 -0
  278. recurvedata/server/__init__.py +0 -0
  279. recurvedata/server/app.py +7 -0
  280. recurvedata/server/connector/__init__.py +0 -0
  281. recurvedata/server/connector/api.py +79 -0
  282. recurvedata/server/connector/schemas.py +28 -0
  283. recurvedata/server/data_service/__init__.py +0 -0
  284. recurvedata/server/data_service/api.py +126 -0
  285. recurvedata/server/data_service/client.py +18 -0
  286. recurvedata/server/data_service/consts.py +1 -0
  287. recurvedata/server/data_service/schemas.py +68 -0
  288. recurvedata/server/data_service/service.py +218 -0
  289. recurvedata/server/dbt/__init__.py +0 -0
  290. recurvedata/server/dbt/api.py +116 -0
  291. recurvedata/server/error_code.py +49 -0
  292. recurvedata/server/exceptions.py +19 -0
  293. recurvedata/server/executor/__init__.py +0 -0
  294. recurvedata/server/executor/api.py +37 -0
  295. recurvedata/server/executor/schemas.py +30 -0
  296. recurvedata/server/executor/service.py +220 -0
  297. recurvedata/server/main.py +32 -0
  298. recurvedata/server/schedulers/__init__.py +0 -0
  299. recurvedata/server/schedulers/api.py +252 -0
  300. recurvedata/server/schedulers/schemas.py +50 -0
  301. recurvedata/server/schemas.py +50 -0
  302. recurvedata/utils/__init__.py +15 -0
  303. recurvedata/utils/_typer.py +61 -0
  304. recurvedata/utils/attrdict.py +19 -0
  305. recurvedata/utils/command_helper.py +20 -0
  306. recurvedata/utils/compat.py +12 -0
  307. recurvedata/utils/compression.py +203 -0
  308. recurvedata/utils/crontab.py +42 -0
  309. recurvedata/utils/crypto_util.py +305 -0
  310. recurvedata/utils/dataclass.py +11 -0
  311. recurvedata/utils/date_time.py +464 -0
  312. recurvedata/utils/dispatch.py +114 -0
  313. recurvedata/utils/email_util.py +104 -0
  314. recurvedata/utils/files.py +386 -0
  315. recurvedata/utils/helpers.py +170 -0
  316. recurvedata/utils/httputil.py +117 -0
  317. recurvedata/utils/imports.py +132 -0
  318. recurvedata/utils/json.py +80 -0
  319. recurvedata/utils/log.py +117 -0
  320. recurvedata/utils/log_capture.py +153 -0
  321. recurvedata/utils/mp.py +178 -0
  322. recurvedata/utils/normalizer.py +102 -0
  323. recurvedata/utils/redis_lock.py +474 -0
  324. recurvedata/utils/registry.py +54 -0
  325. recurvedata/utils/shell.py +15 -0
  326. recurvedata/utils/singleton.py +33 -0
  327. recurvedata/utils/sql.py +6 -0
  328. recurvedata/utils/timeout.py +28 -0
  329. recurvedata/utils/tracing.py +14 -0
  330. recurvedata_lib-0.1.487.dist-info/METADATA +605 -0
  331. recurvedata_lib-0.1.487.dist-info/RECORD +333 -0
  332. recurvedata_lib-0.1.487.dist-info/WHEEL +5 -0
  333. recurvedata_lib-0.1.487.dist-info/entry_points.txt +6 -0
@@ -0,0 +1,219 @@
1
+ from typing import Any
2
+
3
+ from recurvedata.connectors._register import register_connector_class
4
+ from recurvedata.connectors.datasource import DataSourceWrapper
5
+ from recurvedata.connectors.dbapi import DBAPIBase
6
+ from recurvedata.consts import ConnectorGroup
7
+ from recurvedata.core.translation import _l
8
+
9
+ CONNECTION_TYPE = "clickhouse"
10
+ UI_CONNECTION_TYPE = "ClickHouse"
11
+
12
+
13
+ @register_connector_class([CONNECTION_TYPE, UI_CONNECTION_TYPE])
14
+ class ClickhouseConnector(DBAPIBase):
15
+ SYSTEM_DATABASES = [
16
+ "system",
17
+ "information_schema",
18
+ ]
19
+ connection_type = CONNECTION_TYPE
20
+ ui_connection_type = UI_CONNECTION_TYPE
21
+ setup_extras_require = ["clickhouse-sqlalchemy"]
22
+ driver = "clickhouse+native"
23
+ group = [ConnectorGroup.DESTINATION]
24
+
25
+ # Official ClickHouse data types from documentation
26
+ available_column_types = [
27
+ # Base types from DBAPIBase
28
+ *DBAPIBase.available_column_types,
29
+ # Integer types (official)
30
+ "int8",
31
+ "int16",
32
+ "int32",
33
+ "int64",
34
+ "int128",
35
+ "int256",
36
+ "uint8",
37
+ "uint16",
38
+ "uint32",
39
+ "uint64",
40
+ "uint128",
41
+ "uint256",
42
+ # Float types (official)
43
+ "float32",
44
+ "float64",
45
+ "bfloat16",
46
+ # String types (official)
47
+ "string",
48
+ "fixedstring",
49
+ # Date/Time types (official)
50
+ "date",
51
+ "date32",
52
+ "datetime",
53
+ "datetime64",
54
+ # Boolean type (official)
55
+ "boolean",
56
+ # UUID type (official)
57
+ "uuid",
58
+ # Network types (official)
59
+ "ipv4",
60
+ "ipv6",
61
+ # Complex types (official)
62
+ "array",
63
+ "tuple",
64
+ "map",
65
+ "variant",
66
+ # Enum types (official)
67
+ "enum",
68
+ "enum8",
69
+ "enum16",
70
+ # Wrapper types (official)
71
+ "nullable",
72
+ "lowcardinality",
73
+ # Aggregate function types (official)
74
+ "aggregatefunction",
75
+ "simpleaggregatefunction",
76
+ # Special types (official)
77
+ "nested",
78
+ "dynamic",
79
+ "json",
80
+ # Decimal type (official)
81
+ "decimal",
82
+ "decimal32",
83
+ "decimal64",
84
+ "decimal128",
85
+ "decimal256",
86
+ ]
87
+
88
+ column_type_mapping = {
89
+ "integer": [
90
+ "Int8",
91
+ "Int16",
92
+ "Int32",
93
+ "Int64",
94
+ "Int128",
95
+ "Int256",
96
+ "UInt8",
97
+ "UInt16",
98
+ "UInt32",
99
+ "UInt64",
100
+ "UInt128",
101
+ "UInt256",
102
+ ],
103
+ "string": ["String", "FixedString", "LowCardinality(String)"],
104
+ }
105
+ config_schema = {
106
+ "type": "object",
107
+ "properties": {
108
+ "host": {
109
+ "type": "string",
110
+ "title": _l("Host Address"),
111
+ "default": "127.0.0.1",
112
+ },
113
+ "user": {"type": "string", "title": _l("Username")},
114
+ "password": {"type": "string", "title": _l("Password")},
115
+ "database": {
116
+ "type": "string",
117
+ "title": _l("Database Name"),
118
+ "description": _l("The name of the database to connect to"),
119
+ },
120
+ "port": {
121
+ "type": "number",
122
+ "title": _l("Port Number"),
123
+ "description": _l(
124
+ "Native Protocol port number for the ClickHouse server connection. "
125
+ "Normally, default is 9000 for native protocol, use 9440 if secure SSL/TLS is enabled."
126
+ ),
127
+ "default": 9000,
128
+ },
129
+ "secure": {
130
+ "type": "boolean",
131
+ "title": _l("Use Secure Connection"),
132
+ "description": _l("Enable secure SSL/TLS connection to ClickHouse"),
133
+ "default": False,
134
+ },
135
+ },
136
+ "order": ["host", "port", "user", "password", "database", "secure"],
137
+ "required": [
138
+ "host",
139
+ ],
140
+ "secret": ["password"],
141
+ }
142
+
143
+ def _extract_column_name(self, column_type):
144
+ if column_type.__visit_name__ == "nullable":
145
+ return column_type.nested_type.__visit_name__
146
+ return column_type.__visit_name__
147
+
148
+ def sqlalchemy_column_type_code_to_name(self, type_code: Any, size: int | None = None) -> str:
149
+ """
150
+ Convert SQLAlchemy cursor.description type_code to ClickHouse data type name.
151
+
152
+ ClickHouse Connect uses string type names directly in cursor.description,
153
+ so we can return the type_code as-is if it's a valid ClickHouse type,
154
+ otherwise fall back to a default type.
155
+ """
156
+ if isinstance(type_code, str):
157
+ # ClickHouse Connect returns string type names directly
158
+ type_name = type_code.lower()
159
+
160
+ # Check if it's a valid ClickHouse type
161
+ if type_name in self.available_column_types:
162
+ return type_name
163
+
164
+ # Handle common type mappings for ClickHouse
165
+ type_mapping = {
166
+ # Common SQL type aliases to ClickHouse types
167
+ "int": "int32",
168
+ "integer": "int32",
169
+ "bigint": "int64",
170
+ "smallint": "int16",
171
+ "tinyint": "int8",
172
+ "double": "float64",
173
+ "float": "float32",
174
+ "real": "float32",
175
+ "varchar": "string",
176
+ "char": "string",
177
+ "text": "string",
178
+ "blob": "string",
179
+ "timestamp": "datetime",
180
+ "bool": "boolean",
181
+ # ClickHouse specific mappings for edge cases
182
+ "nothing": "string", # Fallback for Nothing type
183
+ "expression": "string", # Fallback for Expression type
184
+ "set": "string", # Fallback for Set type
185
+ "array(string)": "array",
186
+ "array(date)": "array",
187
+ "array(datetime)": "array",
188
+ "array(float64)": "array",
189
+ "array(float32)": "array",
190
+ "array(int64)": "array",
191
+ "array(int32)": "array",
192
+ }
193
+
194
+ mapped_type = type_mapping.get(type_name)
195
+ if mapped_type and mapped_type in self.available_column_types:
196
+ return mapped_type
197
+
198
+ # For any other type_code format, try to convert to string and check again
199
+ try:
200
+ type_str = str(type_code).lower()
201
+ if type_str in self.available_column_types:
202
+ return type_str
203
+ except (ValueError, TypeError):
204
+ pass
205
+
206
+ # Default fallback
207
+ return "string"
208
+
209
+ def convert_config_to_cube_config(
210
+ self, database: str, schema: str = None, datasource: DataSourceWrapper = None
211
+ ) -> dict:
212
+ config = {
213
+ "type": "clickhouse",
214
+ "host": self.host,
215
+ "user": datasource.user,
216
+ "password": datasource.password,
217
+ "database": database or self.database,
218
+ }
219
+ return config
@@ -0,0 +1,61 @@
1
+ import requests
2
+
3
+ from recurvedata.connectors._register import register_connector_class
4
+ from recurvedata.connectors.base import RecurveConnectorBase
5
+ from recurvedata.consts import ConnectorGroup
6
+ from recurvedata.core.translation import _l
7
+
8
+ CONNECTION_TYPE = "dingtalk"
9
+ UI_CONNECTION_TYPE = "Ding Talk"
10
+
11
+
12
+ @register_connector_class([CONNECTION_TYPE, UI_CONNECTION_TYPE])
13
+ class DingTalk(RecurveConnectorBase):
14
+ connection_type = CONNECTION_TYPE
15
+ ui_connection_type = UI_CONNECTION_TYPE
16
+ group = [ConnectorGroup.INTEGRATION]
17
+ enabled = False
18
+
19
+ config_schema = {
20
+ "type": "object",
21
+ "properties": {
22
+ "app_key": {"type": "string", "title": _l("DingTalk App Key")},
23
+ "app_secret": {"type": "string", "title": _l("DingTalk App Secret")},
24
+ "phone": {
25
+ "type": "string",
26
+ "title": _l("Phone Number"),
27
+ "description": _l("Phone number associated with the DingTalk account"),
28
+ },
29
+ },
30
+ "order": ["app_key", "app_secret", "phone"],
31
+ "required": ["app_key", "app_secret"],
32
+ "secret": ["app_secret"],
33
+ }
34
+
35
+ def test_connection(self):
36
+ access_token = self.get_token()
37
+ if self.phone:
38
+ self.get_user_id_by_phone(access_token)
39
+
40
+ def get_token(self):
41
+ """
42
+ 获取钉钉的访问令牌
43
+ """
44
+ url = f"https://oapi.dingtalk.com/gettoken?appkey={self.app_key}&appsecret={self.app_secret}"
45
+ resp = requests.get(url)
46
+ data = resp.json()
47
+ if data.get("errcode"):
48
+ raise ValueError(f"get_token fail, response data: {data}")
49
+ return data["access_token"]
50
+
51
+ def get_user_id_by_phone(self, access_token):
52
+ """
53
+ 获取 user id
54
+ """
55
+ url = "https://oapi.dingtalk.com/topapi/v2/user/getbymobile"
56
+ data = {"access_token": access_token, "mobile": self.phone, "support_exclusive_account_search": "true"}
57
+ resp = requests.post(url=url, data=data)
58
+ data = resp.json()
59
+ if data.get("errcode"):
60
+ raise ValueError(f"get_user_id fail, response data: {data}, please check your phone number")
61
+ return data.get("result").get("userid")
@@ -0,0 +1,215 @@
1
+ from functools import cached_property
2
+ from typing import Any
3
+
4
+ from recurvedata.connectors._register import register_connector_class
5
+ from recurvedata.connectors.const import ENV_VAR_DBT_PASSWORD, ENV_VAR_DBT_USER, SSH_TUNNEL_CONFIG_SCHEMA
6
+ from recurvedata.connectors.datasource import DataSourceWrapper
7
+ from recurvedata.connectors.dbapi import DBAPIBase, with_ssh_tunnel
8
+ from recurvedata.consts import ConnectorGroup
9
+ from recurvedata.core.translation import _l
10
+
11
+ CONNECTION_TYPE = "doris"
12
+ UI_CONNECTION_TYPE = "SelectDB(Doris)"
13
+
14
+
15
+ @register_connector_class([CONNECTION_TYPE, UI_CONNECTION_TYPE])
16
+ class ApacheDorisConnector(DBAPIBase):
17
+ SYSTEM_DATABASES = [
18
+ "information_schema",
19
+ "mysql",
20
+ "__internal_schema",
21
+ ]
22
+ connection_type = CONNECTION_TYPE
23
+ ui_connection_type = UI_CONNECTION_TYPE
24
+ setup_extras_require = ["sqlalchemy-doris[pymysql]"]
25
+ driver = "doris+pymysql"
26
+ group = [ConnectorGroup.DESTINATION]
27
+
28
+ config_schema = {
29
+ "type": "object",
30
+ "properties": {
31
+ "host": {
32
+ "type": "string",
33
+ "title": _l("Host Address"),
34
+ "default": "127.0.0.1",
35
+ },
36
+ "user": {"type": "string", "title": _l("Username")},
37
+ "password": {"type": "string", "title": _l("Password")},
38
+ "database": {
39
+ "type": "string",
40
+ "title": _l("Database Name"),
41
+ "description": _l("The name of the database to connect to"),
42
+ },
43
+ "port": {
44
+ "type": "number",
45
+ "title": _l("SelectDB(Doris) Port Number"),
46
+ "description": _l("The port number for connecting to SelectDB(Doris) server on FE"),
47
+ "default": 9030,
48
+ },
49
+ "http_port": {
50
+ "type": "number",
51
+ "title": _l("FE HTTP Port"),
52
+ "description": _l("The HTTP port number for the Doris Frontend (FE) service"),
53
+ "default": 8030,
54
+ },
55
+ "ssh_tunnel": SSH_TUNNEL_CONFIG_SCHEMA,
56
+ },
57
+ "order": ["host", "port", "http_port", "user", "password", "database", "ssh_tunnel"],
58
+ "required": ["host", "http_port"],
59
+ "secret": ["password"],
60
+ }
61
+
62
+ available_column_types = DBAPIBase.available_column_types + [
63
+ # Numeric types
64
+ "tinyint",
65
+ "integer", # alias for int
66
+ "largeint", # 128-bit signed integer
67
+ "numeric", # alias for decimal
68
+ "real", # alias for float
69
+ "double precision", # alias for double
70
+ "bigint unsigned",
71
+ # String types
72
+ "text", # alias for string
73
+ "string", # alias for varchar
74
+ # Date and Time types
75
+ "datetime", # alias for timestamp
76
+ "time",
77
+ # Complex types
78
+ "array",
79
+ "map",
80
+ "struct",
81
+ "variant",
82
+ "json",
83
+ # Special types
84
+ "bitmap",
85
+ "hll",
86
+ "quantile_state",
87
+ "agg_state",
88
+ # Boolean type
89
+ "boolean",
90
+ "bool", # alias for
91
+ # IP types
92
+ "ipv4",
93
+ "ipv6",
94
+ ]
95
+
96
+ column_type_mapping = {
97
+ "integer": ["tinyint", "largeint"],
98
+ "string": ["text", "string"],
99
+ }
100
+
101
+ def convert_config_to_dbt_profile(self, database: str, schema: str = None) -> dict:
102
+ return {
103
+ "host": self.host,
104
+ "port": self.port,
105
+ "username": ENV_VAR_DBT_USER,
106
+ "password": ENV_VAR_DBT_PASSWORD,
107
+ "schema": database or self.database,
108
+ "type": "doris",
109
+ "threads": 10,
110
+ }
111
+
112
+ @with_ssh_tunnel
113
+ def get_tables(self, database: str = None) -> list[str]:
114
+ # todo: update doris inspector in sqlalchemy-doris, which return both views and tables
115
+ table_views: list[str] = super().get_tables(database)
116
+ for view in self.get_views(database):
117
+ if view in table_views:
118
+ table_views.remove(view)
119
+ return table_views
120
+
121
+ @with_ssh_tunnel
122
+ def get_columns(self, table: str, database: str = None) -> list:
123
+ database = database or self.database
124
+ query = f"""
125
+ SELECT
126
+ column_name,
127
+ data_type,
128
+ column_default,
129
+ is_nullable,
130
+ column_comment
131
+ FROM information_schema.columns
132
+ WHERE table_schema = '{database}'
133
+ AND table_name = '{table}'
134
+ """
135
+ column_metas = []
136
+ results = self.fetchall(query)
137
+ for row in results:
138
+ column_metas.append(
139
+ {
140
+ "name": row[0],
141
+ "type": row[1].lower() if row[1] else "",
142
+ "default": row[2],
143
+ "nullable": row[3] == "YES",
144
+ "comment": row[4],
145
+ }
146
+ )
147
+
148
+ return column_metas
149
+
150
+ @cached_property
151
+ @with_ssh_tunnel
152
+ def type_code_mapping(self) -> dict:
153
+ query = "SHOW DATA TYPES"
154
+ rv = self.fetchall(query)
155
+ return {row[0]: row[0] for row in rv}
156
+
157
+ def sqlalchemy_column_type_code_to_name(self, type_code: Any, size: int | None = None) -> str:
158
+ # values refer to https://doris.apache.org/docs/table-design/data-type/
159
+ # values of this mapping must be in available_column_types, or just default as string
160
+ from pymysql.constants import FIELD_TYPE
161
+
162
+ type_code_mapping = {
163
+ FIELD_TYPE.TINY: "tinyint",
164
+ FIELD_TYPE.SHORT: "smallint",
165
+ FIELD_TYPE.LONG: "int",
166
+ FIELD_TYPE.FLOAT: "float",
167
+ FIELD_TYPE.DOUBLE: "double",
168
+ FIELD_TYPE.DECIMAL: "decimal",
169
+ FIELD_TYPE.NEWDECIMAL: "decimal",
170
+ FIELD_TYPE.LONGLONG: "bigint",
171
+ FIELD_TYPE.INT24: "int",
172
+ FIELD_TYPE.DATE: "date",
173
+ FIELD_TYPE.NEWDATE: "date",
174
+ FIELD_TYPE.DATETIME: "datetime",
175
+ FIELD_TYPE.STRING: "varchar",
176
+ FIELD_TYPE.VARCHAR: "varchar",
177
+ FIELD_TYPE.JSON: "json",
178
+ }
179
+ return type_code_mapping.get(type_code, "varchar")
180
+
181
+ def convert_config_to_cube_config(
182
+ self, database: str, schema: str = None, datasource: DataSourceWrapper = None
183
+ ) -> dict:
184
+ return {
185
+ "type": "doris",
186
+ "host": self.host,
187
+ "port": self.port,
188
+ "user": datasource.user,
189
+ "password": datasource.password,
190
+ "database": database or self.database,
191
+ }
192
+
193
+ @classmethod
194
+ def order_sql(cls, sql: str, orders: list[dict[str, str]] = None):
195
+ base_sql = f"SELECT * FROM ({sql}) AS _recurve_limit_subquery"
196
+ if orders:
197
+ order_clauses = [f"{order['field']} {order['order']}" for order in orders]
198
+ base_sql += " ORDER BY " + ", ".join(order_clauses)
199
+ return base_sql
200
+
201
+ @classmethod
202
+ def limit_sql(cls, sql: str, limit: int = 100, orders: list[dict[str, str]] | None = None, offset: int = 0) -> str:
203
+ """
204
+ the sqlglot will convert `timestamp` to `datetime`,
205
+ which cause this sql: `cast(field as timestamp) as field` to be error in dbt build but success in preview.
206
+ args:
207
+ sql: the sql to be limited
208
+ limit: the limit of the sql
209
+ orders: the orders of the sql(list[dict[str, str]]), each dict contains `field` and `order`, used in data service preview
210
+ """
211
+ base_sql = cls.order_sql(sql, orders)
212
+ if offset:
213
+ return f"{base_sql} LIMIT {offset}, {limit}"
214
+
215
+ return f"{base_sql} LIMIT {limit}"
@@ -0,0 +1,62 @@
1
+ from sqlalchemy.engine import URL
2
+
3
+ from recurvedata.connectors._register import register_connector_class
4
+ from recurvedata.connectors.dbapi import DBAPIBase
5
+ from recurvedata.consts import ConnectorGroup
6
+ from recurvedata.core.translation import _l
7
+
8
+ CONNECTION_TYPE = "elasticsearch"
9
+ UI_CONNECTION_TYPE = "Elasticsearch"
10
+
11
+
12
+ @register_connector_class([CONNECTION_TYPE, UI_CONNECTION_TYPE])
13
+ class ElasticSearchConnector(DBAPIBase):
14
+ connection_type = CONNECTION_TYPE
15
+ ui_connection_type = UI_CONNECTION_TYPE
16
+ group = [ConnectorGroup.DESTINATION]
17
+
18
+ setup_extras_require = ["elasticsearch-dbapi"]
19
+ driver = "elasticsearch"
20
+ config_schema = {
21
+ "type": "object",
22
+ "properties": {
23
+ "host": {
24
+ "type": "string",
25
+ "title": _l("Host Address"),
26
+ "default": "127.0.0.1",
27
+ },
28
+ "port": {
29
+ "type": "number",
30
+ "title": _l("Port Number"),
31
+ "default": 9200,
32
+ },
33
+ "user": {"type": "string", "title": _l("Username")},
34
+ "password": {"type": "string", "title": _l("Password")},
35
+ },
36
+ "order": [
37
+ "host",
38
+ "port",
39
+ "user",
40
+ "password",
41
+ ],
42
+ "required": [
43
+ "host",
44
+ ],
45
+ "secret": ["password"],
46
+ }
47
+
48
+ @property
49
+ def user(self): # todo
50
+ return self.conf.get("user")
51
+
52
+ @property
53
+ def password(self): # todo
54
+ return self.conf.get("password")
55
+
56
+ @property
57
+ def sqlalchemy_url(self):
58
+ return URL(self.driver, self.user, self.password, self.host, self.port)
59
+
60
+ @classmethod
61
+ def get_sql_operator_types(cls):
62
+ return []
@@ -0,0 +1,65 @@
1
+ try:
2
+ from larksuiteoapi import DOMAIN_FEISHU, LEVEL_DEBUG, Config
3
+ from larksuiteoapi.service.bot.v3.api import Service as BotV3Service
4
+ except ImportError:
5
+ pass
6
+
7
+ from recurvedata.connectors._register import register_connector_class
8
+ from recurvedata.connectors.base import RecurveConnectorBase
9
+ from recurvedata.consts import ConnectorGroup
10
+ from recurvedata.core.translation import _l
11
+
12
+ CONNECTION_TYPE = "feishu_bot"
13
+ UI_CONNECTION_TYPE = "Feishu"
14
+
15
+
16
+ @register_connector_class([CONNECTION_TYPE, UI_CONNECTION_TYPE])
17
+ class FeiShuBot(RecurveConnectorBase):
18
+ setup_extras_require = ["larksuite-oapi"]
19
+ connection_type = CONNECTION_TYPE
20
+ ui_connection_type = UI_CONNECTION_TYPE
21
+ group = [ConnectorGroup.INTEGRATION]
22
+
23
+ config_schema = {
24
+ "type": "object",
25
+ "properties": {
26
+ "app_id": {"type": "string", "title": _l("Feishu Bot App ID")},
27
+ "app_secret": {"type": "string", "title": _l("Feishu Bot App Secret")},
28
+ },
29
+ "order": [
30
+ "app_id",
31
+ "app_secret",
32
+ ],
33
+ "required": [
34
+ "app_id",
35
+ "app_secret",
36
+ ],
37
+ "secret": [
38
+ "app_secret",
39
+ ],
40
+ }
41
+
42
+ @property
43
+ def app_id(self):
44
+ return self.conf["app_id"]
45
+
46
+ @property
47
+ def app_secret(self):
48
+ return self.conf["app_secret"]
49
+
50
+ @property
51
+ def feishu_conf(self):
52
+ if hasattr(self, "_feishu_conf"):
53
+ return self._feishu_conf
54
+ self.init_config()
55
+ return self._feishu_conf
56
+
57
+ def init_config(self):
58
+ app_settings = Config.new_internal_app_settings(app_id=self.app_id, app_secret=self.app_secret)
59
+ self._feishu_conf = Config(DOMAIN_FEISHU, app_settings, log_level=LEVEL_DEBUG)
60
+
61
+ def test_connection(self):
62
+ service = BotV3Service(self.feishu_conf)
63
+ resp = service.bots.get().do()
64
+ if resp.code != 0:
65
+ raise ValueError(f"{resp.msg} {resp.error}")
@@ -0,0 +1,50 @@
1
+ try:
2
+ from fsspec.implementations.ftp import FTPFileSystem
3
+ except ImportError:
4
+ FTPFileSystem = None
5
+
6
+ from recurvedata.connectors._register import register_connector_class
7
+ from recurvedata.connectors.ftp import FTPMixin
8
+ from recurvedata.consts import ConnectorGroup
9
+ from recurvedata.core.translation import _l
10
+
11
+ CONNECTION_TYPE = "ftp"
12
+ UI_CONNECTION_TYPE = "FTP"
13
+
14
+
15
+ @register_connector_class([CONNECTION_TYPE, UI_CONNECTION_TYPE])
16
+ class FTP(FTPMixin):
17
+ connection_type = CONNECTION_TYPE
18
+ ui_connection_type = UI_CONNECTION_TYPE
19
+ group = [ConnectorGroup.DESTINATION]
20
+
21
+ config_schema = {
22
+ "type": "object",
23
+ "properties": {
24
+ "host": {
25
+ "type": "string",
26
+ "title": _l("Host Address"),
27
+ "default": "127.0.0.1",
28
+ },
29
+ "user": {"type": "string", "title": _l("Username")},
30
+ "password": {"type": "string", "title": _l("Password")},
31
+ "port": {
32
+ "type": "number",
33
+ "title": _l("Port Number"),
34
+ "default": 21,
35
+ },
36
+ },
37
+ "order": [
38
+ "host",
39
+ "port",
40
+ "user",
41
+ "password",
42
+ ],
43
+ "required": ["host", "port"],
44
+ "secret": ["password"],
45
+ }
46
+
47
+ def init_connection(self, conf) -> FTPFileSystem:
48
+ con = FTPFileSystem(host=conf["host"], port=conf["port"], user=conf["user"], password=conf["password"])
49
+ self.connector = con
50
+ return con