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.
- recurvedata/__init__.py +0 -0
- recurvedata/__version__.py +1 -0
- recurvedata/client/__init__.py +3 -0
- recurvedata/client/client.py +150 -0
- recurvedata/client/server_client.py +91 -0
- recurvedata/config.py +99 -0
- recurvedata/connectors/__init__.py +20 -0
- recurvedata/connectors/_register.py +46 -0
- recurvedata/connectors/base.py +111 -0
- recurvedata/connectors/config_schema.py +1575 -0
- recurvedata/connectors/connectors/__init__.py +0 -0
- recurvedata/connectors/connectors/aliyun_access_key.py +30 -0
- recurvedata/connectors/connectors/auth.py +44 -0
- recurvedata/connectors/connectors/azure_blob.py +89 -0
- recurvedata/connectors/connectors/azure_synapse.py +79 -0
- recurvedata/connectors/connectors/bigquery.py +359 -0
- recurvedata/connectors/connectors/clickhouse.py +219 -0
- recurvedata/connectors/connectors/dingtalk.py +61 -0
- recurvedata/connectors/connectors/doris.py +215 -0
- recurvedata/connectors/connectors/es.py +62 -0
- recurvedata/connectors/connectors/feishu.py +65 -0
- recurvedata/connectors/connectors/ftp.py +50 -0
- recurvedata/connectors/connectors/generic.py +49 -0
- recurvedata/connectors/connectors/google_cloud_storage.py +115 -0
- recurvedata/connectors/connectors/google_service_account.py +225 -0
- recurvedata/connectors/connectors/hive.py +207 -0
- recurvedata/connectors/connectors/impala.py +210 -0
- recurvedata/connectors/connectors/jenkins.py +51 -0
- recurvedata/connectors/connectors/mail.py +89 -0
- recurvedata/connectors/connectors/microsoft_fabric.py +284 -0
- recurvedata/connectors/connectors/mongo.py +79 -0
- recurvedata/connectors/connectors/mssql.py +131 -0
- recurvedata/connectors/connectors/mysql.py +191 -0
- recurvedata/connectors/connectors/n8n.py +141 -0
- recurvedata/connectors/connectors/oss.py +74 -0
- recurvedata/connectors/connectors/owncloud.py +36 -0
- recurvedata/connectors/connectors/phoenix.py +36 -0
- recurvedata/connectors/connectors/postgres.py +230 -0
- recurvedata/connectors/connectors/python.py +50 -0
- recurvedata/connectors/connectors/redshift.py +187 -0
- recurvedata/connectors/connectors/s3.py +93 -0
- recurvedata/connectors/connectors/sftp.py +87 -0
- recurvedata/connectors/connectors/slack.py +35 -0
- recurvedata/connectors/connectors/spark.py +99 -0
- recurvedata/connectors/connectors/starrocks.py +175 -0
- recurvedata/connectors/connectors/tencent_cos.py +40 -0
- recurvedata/connectors/connectors/tidb.py +49 -0
- recurvedata/connectors/const.py +315 -0
- recurvedata/connectors/datasource.py +189 -0
- recurvedata/connectors/dbapi.py +469 -0
- recurvedata/connectors/fs.py +66 -0
- recurvedata/connectors/ftp.py +40 -0
- recurvedata/connectors/object_store.py +60 -0
- recurvedata/connectors/pigeon.py +172 -0
- recurvedata/connectors/proxy.py +104 -0
- recurvedata/connectors/service.py +223 -0
- recurvedata/connectors/utils.py +47 -0
- recurvedata/consts.py +49 -0
- recurvedata/core/__init__.py +0 -0
- recurvedata/core/config.py +46 -0
- recurvedata/core/configurable.py +27 -0
- recurvedata/core/consts.py +2 -0
- recurvedata/core/templating.py +206 -0
- recurvedata/core/tracing.py +223 -0
- recurvedata/core/transformer.py +186 -0
- recurvedata/core/translation.py +91 -0
- recurvedata/dbt/client.py +97 -0
- recurvedata/dbt/consts.py +99 -0
- recurvedata/dbt/cosmos_utils.py +275 -0
- recurvedata/dbt/error_codes.py +18 -0
- recurvedata/dbt/schemas.py +98 -0
- recurvedata/dbt/service.py +451 -0
- recurvedata/dbt/utils.py +246 -0
- recurvedata/error_codes.py +71 -0
- recurvedata/exceptions.py +72 -0
- recurvedata/executors/__init__.py +4 -0
- recurvedata/executors/cli/__init__.py +7 -0
- recurvedata/executors/cli/connector.py +117 -0
- recurvedata/executors/cli/dbt.py +118 -0
- recurvedata/executors/cli/main.py +82 -0
- recurvedata/executors/cli/parameters.py +18 -0
- recurvedata/executors/client.py +190 -0
- recurvedata/executors/consts.py +50 -0
- recurvedata/executors/debug_executor.py +100 -0
- recurvedata/executors/executor.py +300 -0
- recurvedata/executors/link_executor.py +189 -0
- recurvedata/executors/models.py +34 -0
- recurvedata/executors/schemas.py +222 -0
- recurvedata/executors/service/__init__.py +0 -0
- recurvedata/executors/service/connector.py +380 -0
- recurvedata/executors/utils.py +172 -0
- recurvedata/filestorage/__init__.py +11 -0
- recurvedata/filestorage/_factory.py +33 -0
- recurvedata/filestorage/backends/__init__.py +0 -0
- recurvedata/filestorage/backends/fsspec.py +45 -0
- recurvedata/filestorage/backends/local.py +67 -0
- recurvedata/filestorage/backends/oss.py +56 -0
- recurvedata/filestorage/interface.py +84 -0
- recurvedata/operators/__init__.py +10 -0
- recurvedata/operators/base.py +28 -0
- recurvedata/operators/config.py +21 -0
- recurvedata/operators/context.py +255 -0
- recurvedata/operators/dbt_operator/__init__.py +2 -0
- recurvedata/operators/dbt_operator/model_pipeline_link_operator.py +55 -0
- recurvedata/operators/dbt_operator/operator.py +353 -0
- recurvedata/operators/link_operator/__init__.py +1 -0
- recurvedata/operators/link_operator/operator.py +120 -0
- recurvedata/operators/models.py +55 -0
- recurvedata/operators/notify_operator/__init__.py +1 -0
- recurvedata/operators/notify_operator/operator.py +180 -0
- recurvedata/operators/operator.py +119 -0
- recurvedata/operators/python_operator/__init__.py +1 -0
- recurvedata/operators/python_operator/operator.py +132 -0
- recurvedata/operators/sensor_operator/__init__.py +1 -0
- recurvedata/operators/sensor_operator/airflow_utils.py +63 -0
- recurvedata/operators/sensor_operator/operator.py +172 -0
- recurvedata/operators/spark_operator/__init__.py +1 -0
- recurvedata/operators/spark_operator/operator.py +200 -0
- recurvedata/operators/spark_operator/spark_sample.py +47 -0
- recurvedata/operators/sql_operator/__init__.py +1 -0
- recurvedata/operators/sql_operator/operator.py +90 -0
- recurvedata/operators/task.py +211 -0
- recurvedata/operators/transfer_operator/__init__.py +40 -0
- recurvedata/operators/transfer_operator/const.py +10 -0
- recurvedata/operators/transfer_operator/dump_aliyun_sls.py +82 -0
- recurvedata/operators/transfer_operator/dump_sheet_task_base.py +292 -0
- recurvedata/operators/transfer_operator/dump_task_cass.py +155 -0
- recurvedata/operators/transfer_operator/dump_task_dbapi.py +209 -0
- recurvedata/operators/transfer_operator/dump_task_es.py +113 -0
- recurvedata/operators/transfer_operator/dump_task_feishu_sheet.py +114 -0
- recurvedata/operators/transfer_operator/dump_task_ftp.py +234 -0
- recurvedata/operators/transfer_operator/dump_task_google_sheet.py +66 -0
- recurvedata/operators/transfer_operator/dump_task_mongodb.py +168 -0
- recurvedata/operators/transfer_operator/dump_task_oss.py +285 -0
- recurvedata/operators/transfer_operator/dump_task_python.py +212 -0
- recurvedata/operators/transfer_operator/dump_task_s3.py +270 -0
- recurvedata/operators/transfer_operator/dump_task_sftp.py +229 -0
- recurvedata/operators/transfer_operator/load_task_aliyun_oss.py +107 -0
- recurvedata/operators/transfer_operator/load_task_azure_blob.py +115 -0
- recurvedata/operators/transfer_operator/load_task_azure_synapse.py +90 -0
- recurvedata/operators/transfer_operator/load_task_clickhouse.py +167 -0
- recurvedata/operators/transfer_operator/load_task_doris.py +164 -0
- recurvedata/operators/transfer_operator/load_task_email.py +188 -0
- recurvedata/operators/transfer_operator/load_task_es.py +86 -0
- recurvedata/operators/transfer_operator/load_task_filebrowser.py +151 -0
- recurvedata/operators/transfer_operator/load_task_ftp.py +19 -0
- recurvedata/operators/transfer_operator/load_task_google_bigquery.py +90 -0
- recurvedata/operators/transfer_operator/load_task_google_cloud_storage.py +127 -0
- recurvedata/operators/transfer_operator/load_task_google_sheet.py +130 -0
- recurvedata/operators/transfer_operator/load_task_hive.py +158 -0
- recurvedata/operators/transfer_operator/load_task_microsoft_fabric.py +105 -0
- recurvedata/operators/transfer_operator/load_task_mssql.py +153 -0
- recurvedata/operators/transfer_operator/load_task_mysql.py +157 -0
- recurvedata/operators/transfer_operator/load_task_owncloud.py +135 -0
- recurvedata/operators/transfer_operator/load_task_postgresql.py +109 -0
- recurvedata/operators/transfer_operator/load_task_qcloud_cos.py +119 -0
- recurvedata/operators/transfer_operator/load_task_recurve_data_prep.py +75 -0
- recurvedata/operators/transfer_operator/load_task_redshift.py +95 -0
- recurvedata/operators/transfer_operator/load_task_s3.py +150 -0
- recurvedata/operators/transfer_operator/load_task_sftp.py +90 -0
- recurvedata/operators/transfer_operator/load_task_starrocks.py +169 -0
- recurvedata/operators/transfer_operator/load_task_yicrowds.py +97 -0
- recurvedata/operators/transfer_operator/mixin.py +31 -0
- recurvedata/operators/transfer_operator/operator.py +231 -0
- recurvedata/operators/transfer_operator/task.py +223 -0
- recurvedata/operators/transfer_operator/utils.py +134 -0
- recurvedata/operators/ui.py +80 -0
- recurvedata/operators/utils/__init__.py +51 -0
- recurvedata/operators/utils/file_factory.py +150 -0
- recurvedata/operators/utils/fs.py +10 -0
- recurvedata/operators/utils/lineage.py +265 -0
- recurvedata/operators/web_init.py +15 -0
- recurvedata/pigeon/connector/__init__.py +294 -0
- recurvedata/pigeon/connector/_registry.py +17 -0
- recurvedata/pigeon/connector/aliyun_oss.py +80 -0
- recurvedata/pigeon/connector/awss3.py +123 -0
- recurvedata/pigeon/connector/azure_blob.py +176 -0
- recurvedata/pigeon/connector/azure_synapse.py +51 -0
- recurvedata/pigeon/connector/cass.py +151 -0
- recurvedata/pigeon/connector/clickhouse.py +403 -0
- recurvedata/pigeon/connector/clickhouse_native.py +351 -0
- recurvedata/pigeon/connector/dbapi.py +571 -0
- recurvedata/pigeon/connector/doris.py +166 -0
- recurvedata/pigeon/connector/es.py +176 -0
- recurvedata/pigeon/connector/feishu.py +1135 -0
- recurvedata/pigeon/connector/ftp.py +163 -0
- recurvedata/pigeon/connector/google_bigquery.py +283 -0
- recurvedata/pigeon/connector/google_cloud_storage.py +130 -0
- recurvedata/pigeon/connector/hbase_phoenix.py +108 -0
- recurvedata/pigeon/connector/hdfs.py +204 -0
- recurvedata/pigeon/connector/hive_impala.py +383 -0
- recurvedata/pigeon/connector/microsoft_fabric.py +95 -0
- recurvedata/pigeon/connector/mongodb.py +56 -0
- recurvedata/pigeon/connector/mssql.py +467 -0
- recurvedata/pigeon/connector/mysql.py +175 -0
- recurvedata/pigeon/connector/owncloud.py +92 -0
- recurvedata/pigeon/connector/postgresql.py +267 -0
- recurvedata/pigeon/connector/power_bi.py +179 -0
- recurvedata/pigeon/connector/qcloud_cos.py +79 -0
- recurvedata/pigeon/connector/redshift.py +123 -0
- recurvedata/pigeon/connector/sftp.py +73 -0
- recurvedata/pigeon/connector/sqlite.py +42 -0
- recurvedata/pigeon/connector/starrocks.py +144 -0
- recurvedata/pigeon/connector/tableau.py +162 -0
- recurvedata/pigeon/const.py +21 -0
- recurvedata/pigeon/csv.py +172 -0
- recurvedata/pigeon/docs/datasources-example.json +82 -0
- recurvedata/pigeon/docs/images/pigeon_design.png +0 -0
- recurvedata/pigeon/docs/lightweight-data-sync-solution.md +111 -0
- recurvedata/pigeon/dumper/__init__.py +171 -0
- recurvedata/pigeon/dumper/aliyun_sls.py +415 -0
- recurvedata/pigeon/dumper/base.py +141 -0
- recurvedata/pigeon/dumper/cass.py +213 -0
- recurvedata/pigeon/dumper/dbapi.py +346 -0
- recurvedata/pigeon/dumper/es.py +112 -0
- recurvedata/pigeon/dumper/ftp.py +64 -0
- recurvedata/pigeon/dumper/mongodb.py +103 -0
- recurvedata/pigeon/handler/__init__.py +4 -0
- recurvedata/pigeon/handler/base.py +153 -0
- recurvedata/pigeon/handler/csv_handler.py +290 -0
- recurvedata/pigeon/loader/__init__.py +87 -0
- recurvedata/pigeon/loader/base.py +83 -0
- recurvedata/pigeon/loader/csv_to_azure_synapse.py +214 -0
- recurvedata/pigeon/loader/csv_to_clickhouse.py +152 -0
- recurvedata/pigeon/loader/csv_to_doris.py +215 -0
- recurvedata/pigeon/loader/csv_to_es.py +51 -0
- recurvedata/pigeon/loader/csv_to_google_bigquery.py +169 -0
- recurvedata/pigeon/loader/csv_to_hive.py +468 -0
- recurvedata/pigeon/loader/csv_to_microsoft_fabric.py +242 -0
- recurvedata/pigeon/loader/csv_to_mssql.py +174 -0
- recurvedata/pigeon/loader/csv_to_mysql.py +180 -0
- recurvedata/pigeon/loader/csv_to_postgresql.py +248 -0
- recurvedata/pigeon/loader/csv_to_redshift.py +240 -0
- recurvedata/pigeon/loader/csv_to_starrocks.py +233 -0
- recurvedata/pigeon/meta.py +116 -0
- recurvedata/pigeon/row_factory.py +42 -0
- recurvedata/pigeon/schema/__init__.py +124 -0
- recurvedata/pigeon/schema/types.py +13 -0
- recurvedata/pigeon/sync.py +283 -0
- recurvedata/pigeon/transformer.py +146 -0
- recurvedata/pigeon/utils/__init__.py +134 -0
- recurvedata/pigeon/utils/bloomfilter.py +181 -0
- recurvedata/pigeon/utils/date_time.py +323 -0
- recurvedata/pigeon/utils/escape.py +15 -0
- recurvedata/pigeon/utils/fs.py +266 -0
- recurvedata/pigeon/utils/json.py +44 -0
- recurvedata/pigeon/utils/keyed_tuple.py +85 -0
- recurvedata/pigeon/utils/mp.py +156 -0
- recurvedata/pigeon/utils/sql.py +328 -0
- recurvedata/pigeon/utils/timing.py +155 -0
- recurvedata/provider_manager.py +0 -0
- recurvedata/providers/__init__.py +0 -0
- recurvedata/providers/dbapi/__init__.py +0 -0
- recurvedata/providers/flywheel/__init__.py +0 -0
- recurvedata/providers/mysql/__init__.py +0 -0
- recurvedata/schedulers/__init__.py +1 -0
- recurvedata/schedulers/airflow.py +974 -0
- recurvedata/schedulers/airflow_db_process.py +331 -0
- recurvedata/schedulers/airflow_operators.py +61 -0
- recurvedata/schedulers/airflow_plugin.py +9 -0
- recurvedata/schedulers/airflow_trigger_dag_patch.py +117 -0
- recurvedata/schedulers/base.py +99 -0
- recurvedata/schedulers/cli.py +228 -0
- recurvedata/schedulers/client.py +56 -0
- recurvedata/schedulers/consts.py +52 -0
- recurvedata/schedulers/debug_celery.py +62 -0
- recurvedata/schedulers/model.py +63 -0
- recurvedata/schedulers/schemas.py +97 -0
- recurvedata/schedulers/service.py +20 -0
- recurvedata/schedulers/system_dags.py +59 -0
- recurvedata/schedulers/task_status.py +279 -0
- recurvedata/schedulers/utils.py +73 -0
- recurvedata/schema/__init__.py +0 -0
- recurvedata/schema/field.py +88 -0
- recurvedata/schema/schema.py +55 -0
- recurvedata/schema/types.py +17 -0
- recurvedata/schema.py +0 -0
- recurvedata/server/__init__.py +0 -0
- recurvedata/server/app.py +7 -0
- recurvedata/server/connector/__init__.py +0 -0
- recurvedata/server/connector/api.py +79 -0
- recurvedata/server/connector/schemas.py +28 -0
- recurvedata/server/data_service/__init__.py +0 -0
- recurvedata/server/data_service/api.py +126 -0
- recurvedata/server/data_service/client.py +18 -0
- recurvedata/server/data_service/consts.py +1 -0
- recurvedata/server/data_service/schemas.py +68 -0
- recurvedata/server/data_service/service.py +218 -0
- recurvedata/server/dbt/__init__.py +0 -0
- recurvedata/server/dbt/api.py +116 -0
- recurvedata/server/error_code.py +49 -0
- recurvedata/server/exceptions.py +19 -0
- recurvedata/server/executor/__init__.py +0 -0
- recurvedata/server/executor/api.py +37 -0
- recurvedata/server/executor/schemas.py +30 -0
- recurvedata/server/executor/service.py +220 -0
- recurvedata/server/main.py +32 -0
- recurvedata/server/schedulers/__init__.py +0 -0
- recurvedata/server/schedulers/api.py +252 -0
- recurvedata/server/schedulers/schemas.py +50 -0
- recurvedata/server/schemas.py +50 -0
- recurvedata/utils/__init__.py +15 -0
- recurvedata/utils/_typer.py +61 -0
- recurvedata/utils/attrdict.py +19 -0
- recurvedata/utils/command_helper.py +20 -0
- recurvedata/utils/compat.py +12 -0
- recurvedata/utils/compression.py +203 -0
- recurvedata/utils/crontab.py +42 -0
- recurvedata/utils/crypto_util.py +305 -0
- recurvedata/utils/dataclass.py +11 -0
- recurvedata/utils/date_time.py +464 -0
- recurvedata/utils/dispatch.py +114 -0
- recurvedata/utils/email_util.py +104 -0
- recurvedata/utils/files.py +386 -0
- recurvedata/utils/helpers.py +170 -0
- recurvedata/utils/httputil.py +117 -0
- recurvedata/utils/imports.py +132 -0
- recurvedata/utils/json.py +80 -0
- recurvedata/utils/log.py +117 -0
- recurvedata/utils/log_capture.py +153 -0
- recurvedata/utils/mp.py +178 -0
- recurvedata/utils/normalizer.py +102 -0
- recurvedata/utils/redis_lock.py +474 -0
- recurvedata/utils/registry.py +54 -0
- recurvedata/utils/shell.py +15 -0
- recurvedata/utils/singleton.py +33 -0
- recurvedata/utils/sql.py +6 -0
- recurvedata/utils/timeout.py +28 -0
- recurvedata/utils/tracing.py +14 -0
- recurvedata_lib-0.1.487.dist-info/METADATA +605 -0
- recurvedata_lib-0.1.487.dist-info/RECORD +333 -0
- recurvedata_lib-0.1.487.dist-info/WHEEL +5 -0
- 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
|