datus-snowflake 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- datus_snowflake-0.1.0/.gitignore +137 -0
- datus_snowflake-0.1.0/PKG-INFO +238 -0
- datus_snowflake-0.1.0/README.md +224 -0
- datus_snowflake-0.1.0/datus_snowflake/__init__.py +18 -0
- datus_snowflake-0.1.0/datus_snowflake/config.py +22 -0
- datus_snowflake-0.1.0/datus_snowflake/connector.py +884 -0
- datus_snowflake-0.1.0/pyproject.toml +30 -0
- datus_snowflake-0.1.0/tests/__init__.py +0 -0
- datus_snowflake-0.1.0/tests/test_connector.py +315 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
pip-wheel-metadata/
|
|
24
|
+
share/python-wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
MANIFEST
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
*.manifest
|
|
32
|
+
*.spec
|
|
33
|
+
|
|
34
|
+
# Installer logs
|
|
35
|
+
pip-log.txt
|
|
36
|
+
pip-delete-this-directory.txt
|
|
37
|
+
|
|
38
|
+
# Unit test / coverage reports
|
|
39
|
+
htmlcov/
|
|
40
|
+
.tox/
|
|
41
|
+
.nox/
|
|
42
|
+
.coverage
|
|
43
|
+
.coverage.*
|
|
44
|
+
.cache
|
|
45
|
+
nosetests.xml
|
|
46
|
+
coverage.xml
|
|
47
|
+
*.cover
|
|
48
|
+
*.py,cover
|
|
49
|
+
.hypothesis/
|
|
50
|
+
.pytest_cache/
|
|
51
|
+
|
|
52
|
+
# Translations
|
|
53
|
+
*.mo
|
|
54
|
+
*.pot
|
|
55
|
+
|
|
56
|
+
# Django stuff:
|
|
57
|
+
*.log
|
|
58
|
+
local_settings.py
|
|
59
|
+
db.sqlite3
|
|
60
|
+
db.sqlite3-journal
|
|
61
|
+
|
|
62
|
+
# Flask stuff:
|
|
63
|
+
instance/
|
|
64
|
+
.webassets-cache
|
|
65
|
+
|
|
66
|
+
# Scrapy stuff:
|
|
67
|
+
.scrapy
|
|
68
|
+
|
|
69
|
+
# Sphinx documentation
|
|
70
|
+
docs/_build/
|
|
71
|
+
|
|
72
|
+
# PyBuilder
|
|
73
|
+
target/
|
|
74
|
+
|
|
75
|
+
# Jupyter Notebook
|
|
76
|
+
.ipynb_checkpoints
|
|
77
|
+
|
|
78
|
+
# IPython
|
|
79
|
+
profile_default/
|
|
80
|
+
ipython_config.py
|
|
81
|
+
|
|
82
|
+
# pyenv
|
|
83
|
+
.python-version
|
|
84
|
+
|
|
85
|
+
# pipenv
|
|
86
|
+
Pipfile.lock
|
|
87
|
+
|
|
88
|
+
# uv
|
|
89
|
+
uv.lock
|
|
90
|
+
|
|
91
|
+
# PEP 582
|
|
92
|
+
__pypackages__/
|
|
93
|
+
|
|
94
|
+
# Celery stuff
|
|
95
|
+
celerybeat-schedule
|
|
96
|
+
celerybeat.pid
|
|
97
|
+
|
|
98
|
+
# SageMath parsed files
|
|
99
|
+
*.sage.py
|
|
100
|
+
|
|
101
|
+
# Environments
|
|
102
|
+
.env
|
|
103
|
+
.venv
|
|
104
|
+
env/
|
|
105
|
+
venv/
|
|
106
|
+
ENV/
|
|
107
|
+
env.bak/
|
|
108
|
+
venv.bak/
|
|
109
|
+
|
|
110
|
+
# Spyder project settings
|
|
111
|
+
.spyderproject
|
|
112
|
+
.spyproject
|
|
113
|
+
|
|
114
|
+
# Rope project settings
|
|
115
|
+
.ropeproject
|
|
116
|
+
|
|
117
|
+
# mkdocs documentation
|
|
118
|
+
/site
|
|
119
|
+
|
|
120
|
+
# mypy
|
|
121
|
+
.mypy_cache/
|
|
122
|
+
.dmypy.json
|
|
123
|
+
dmypy.json
|
|
124
|
+
|
|
125
|
+
# Pyre type checker
|
|
126
|
+
.pyre/
|
|
127
|
+
|
|
128
|
+
# IDEs
|
|
129
|
+
.vscode/
|
|
130
|
+
.idea/
|
|
131
|
+
*.swp
|
|
132
|
+
*.swo
|
|
133
|
+
*~
|
|
134
|
+
|
|
135
|
+
# OS
|
|
136
|
+
.DS_Store
|
|
137
|
+
Thumbs.db
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: datus-snowflake
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Snowflake adapter for Datus Agent
|
|
5
|
+
Author-email: DatusAI <support@datus.ai>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Requires-Python: >=3.8
|
|
8
|
+
Requires-Dist: datus-agent>0.2.1
|
|
9
|
+
Requires-Dist: snowflake-connector-python>=3.6.0
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
12
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# Datus Snowflake Adapter
|
|
16
|
+
|
|
17
|
+
Snowflake database adapter for Datus Agent, providing native Snowflake connector support.
|
|
18
|
+
|
|
19
|
+
## Features
|
|
20
|
+
|
|
21
|
+
- **Native Snowflake SDK**: Uses `snowflake-connector-python` for optimal performance
|
|
22
|
+
- **Full Snowflake Support**: Databases, schemas, tables, views, and materialized views
|
|
23
|
+
- **Efficient Metadata Retrieval**: Uses SHOW commands for fast metadata queries
|
|
24
|
+
- **Arrow-based Execution**: High-performance query execution with Apache Arrow
|
|
25
|
+
- **Multiple Result Formats**: CSV, Pandas DataFrame, Arrow Table, and Python list
|
|
26
|
+
- **Complete CRUD Operations**: INSERT, UPDATE, DELETE, and DDL support
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pip install datus-snowflake
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This will automatically install the required dependencies:
|
|
35
|
+
- `datus-agent>=0.3.0`
|
|
36
|
+
- `snowflake-connector-python>=3.6.0`
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
### Basic Connection
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from datus_snowflake import SnowflakeConnector
|
|
44
|
+
|
|
45
|
+
# Create connector
|
|
46
|
+
connector = SnowflakeConnector(
|
|
47
|
+
account="myaccount",
|
|
48
|
+
user="myuser",
|
|
49
|
+
password="mypassword",
|
|
50
|
+
warehouse="my_warehouse",
|
|
51
|
+
database="my_database",
|
|
52
|
+
schema="my_schema"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Test connection
|
|
56
|
+
result = connector.test_connection()
|
|
57
|
+
print(result) # {'success': True, 'message': 'Connection successful', 'databases': ''}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Execute Queries
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# Execute query and get CSV result
|
|
64
|
+
result = connector.execute_query("SELECT * FROM users LIMIT 10")
|
|
65
|
+
print(result.sql_return) # CSV string
|
|
66
|
+
|
|
67
|
+
# Execute query and get pandas DataFrame
|
|
68
|
+
result = connector.execute_query("SELECT * FROM users LIMIT 10", result_format="pandas")
|
|
69
|
+
df = result.sql_return
|
|
70
|
+
print(df.head())
|
|
71
|
+
|
|
72
|
+
# Execute query and get Arrow table
|
|
73
|
+
result = connector.execute_query("SELECT * FROM users LIMIT 10", result_format="arrow")
|
|
74
|
+
arrow_table = result.sql_return
|
|
75
|
+
print(arrow_table.schema)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Metadata Operations
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
# Get databases
|
|
82
|
+
databases = connector.get_databases()
|
|
83
|
+
print(f"Databases: {databases}")
|
|
84
|
+
|
|
85
|
+
# Get schemas
|
|
86
|
+
schemas = connector.get_schemas(database_name="my_database")
|
|
87
|
+
print(f"Schemas: {schemas}")
|
|
88
|
+
|
|
89
|
+
# Get tables
|
|
90
|
+
tables = connector.get_tables(database_name="my_database", schema_name="public")
|
|
91
|
+
print(f"Tables: {tables}")
|
|
92
|
+
|
|
93
|
+
# Get views
|
|
94
|
+
views = connector.get_views(database_name="my_database", schema_name="public")
|
|
95
|
+
print(f"Views: {views}")
|
|
96
|
+
|
|
97
|
+
# Get materialized views
|
|
98
|
+
mvs = connector.get_materialized_views(database_name="my_database", schema_name="public")
|
|
99
|
+
print(f"Materialized Views: {mvs}")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Get Table Schema
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# Get table structure
|
|
106
|
+
schema = connector.get_schema(
|
|
107
|
+
database_name="my_database",
|
|
108
|
+
schema_name="public",
|
|
109
|
+
table_name="users"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
for column in schema[:-1]: # Last item is table metadata
|
|
113
|
+
print(f"{column['name']}: {column['type']} (nullable: {column['nullable']})")
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Get DDL Definitions
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
# Get tables with DDL
|
|
120
|
+
tables_with_ddl = connector.get_tables_with_ddl(
|
|
121
|
+
database_name="my_database",
|
|
122
|
+
schema_name="public"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
for table in tables_with_ddl:
|
|
126
|
+
print(f"\nTable: {table['table_name']}")
|
|
127
|
+
print(f"DDL:\n{table['definition']}")
|
|
128
|
+
|
|
129
|
+
# Get views with DDL
|
|
130
|
+
views_with_ddl = connector.get_views_with_ddl(
|
|
131
|
+
database_name="my_database",
|
|
132
|
+
schema_name="public"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
# Get materialized views with DDL
|
|
136
|
+
mvs_with_ddl = connector.get_materialized_views_with_ddl(
|
|
137
|
+
database_name="my_database",
|
|
138
|
+
schema_name="public"
|
|
139
|
+
)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Get Sample Data
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
# Get sample rows from specific tables
|
|
146
|
+
samples = connector.get_sample_rows(
|
|
147
|
+
tables=["users", "orders"],
|
|
148
|
+
top_n=5,
|
|
149
|
+
database_name="my_database",
|
|
150
|
+
schema_name="public"
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
for sample in samples:
|
|
154
|
+
print(f"\nTable: {sample['table_name']}")
|
|
155
|
+
print(sample['sample_rows']) # CSV format
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### CRUD Operations
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
# INSERT
|
|
162
|
+
result = connector.execute_insert(
|
|
163
|
+
"INSERT INTO users (name, email) VALUES ('John', 'john@example.com')"
|
|
164
|
+
)
|
|
165
|
+
print(f"Inserted rows: {result.row_count}")
|
|
166
|
+
|
|
167
|
+
# UPDATE
|
|
168
|
+
result = connector.execute_update(
|
|
169
|
+
"UPDATE users SET email = 'newemail@example.com' WHERE name = 'John'"
|
|
170
|
+
)
|
|
171
|
+
print(f"Updated rows: {result.row_count}")
|
|
172
|
+
|
|
173
|
+
# DELETE
|
|
174
|
+
result = connector.execute_delete(
|
|
175
|
+
"DELETE FROM users WHERE name = 'John'"
|
|
176
|
+
)
|
|
177
|
+
print(f"Deleted rows: {result.row_count}")
|
|
178
|
+
|
|
179
|
+
# DDL
|
|
180
|
+
result = connector.execute_ddl(
|
|
181
|
+
"CREATE TABLE test_table (id INT, name VARCHAR(100))"
|
|
182
|
+
)
|
|
183
|
+
print(f"DDL executed: {result.success}")
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Context Switching
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
# Switch database
|
|
190
|
+
connector.do_switch_context(database_name="another_database")
|
|
191
|
+
|
|
192
|
+
# Switch schema
|
|
193
|
+
connector.do_switch_context(
|
|
194
|
+
database_name="my_database",
|
|
195
|
+
schema_name="another_schema"
|
|
196
|
+
)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Configuration with Datus Agent
|
|
200
|
+
|
|
201
|
+
When using with Datus Agent, the adapter is automatically discovered via entry points:
|
|
202
|
+
|
|
203
|
+
```yaml
|
|
204
|
+
# config.yaml
|
|
205
|
+
database:
|
|
206
|
+
type: snowflake
|
|
207
|
+
account: myaccount
|
|
208
|
+
username: myuser
|
|
209
|
+
password: mypassword
|
|
210
|
+
warehouse: my_warehouse
|
|
211
|
+
database: my_database
|
|
212
|
+
schema: my_schema
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The adapter will be automatically loaded when you use `type: snowflake`.
|
|
216
|
+
|
|
217
|
+
## Architecture
|
|
218
|
+
|
|
219
|
+
This adapter:
|
|
220
|
+
- Inherits from `BaseSqlConnector` in `datus-agent`
|
|
221
|
+
- Uses native Snowflake connector for optimal performance
|
|
222
|
+
- Implements all required abstract methods
|
|
223
|
+
- Provides Snowflake-specific optimizations (SHOW commands, Arrow format)
|
|
224
|
+
|
|
225
|
+
## Development
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# Install in development mode
|
|
229
|
+
cd datus-snowflake
|
|
230
|
+
pip install -e .
|
|
231
|
+
|
|
232
|
+
# Run tests
|
|
233
|
+
pytest tests/
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## License
|
|
237
|
+
|
|
238
|
+
Apache License 2.0
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# Datus Snowflake Adapter
|
|
2
|
+
|
|
3
|
+
Snowflake database adapter for Datus Agent, providing native Snowflake connector support.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Native Snowflake SDK**: Uses `snowflake-connector-python` for optimal performance
|
|
8
|
+
- **Full Snowflake Support**: Databases, schemas, tables, views, and materialized views
|
|
9
|
+
- **Efficient Metadata Retrieval**: Uses SHOW commands for fast metadata queries
|
|
10
|
+
- **Arrow-based Execution**: High-performance query execution with Apache Arrow
|
|
11
|
+
- **Multiple Result Formats**: CSV, Pandas DataFrame, Arrow Table, and Python list
|
|
12
|
+
- **Complete CRUD Operations**: INSERT, UPDATE, DELETE, and DDL support
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install datus-snowflake
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This will automatically install the required dependencies:
|
|
21
|
+
- `datus-agent>=0.3.0`
|
|
22
|
+
- `snowflake-connector-python>=3.6.0`
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Basic Connection
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from datus_snowflake import SnowflakeConnector
|
|
30
|
+
|
|
31
|
+
# Create connector
|
|
32
|
+
connector = SnowflakeConnector(
|
|
33
|
+
account="myaccount",
|
|
34
|
+
user="myuser",
|
|
35
|
+
password="mypassword",
|
|
36
|
+
warehouse="my_warehouse",
|
|
37
|
+
database="my_database",
|
|
38
|
+
schema="my_schema"
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Test connection
|
|
42
|
+
result = connector.test_connection()
|
|
43
|
+
print(result) # {'success': True, 'message': 'Connection successful', 'databases': ''}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Execute Queries
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
# Execute query and get CSV result
|
|
50
|
+
result = connector.execute_query("SELECT * FROM users LIMIT 10")
|
|
51
|
+
print(result.sql_return) # CSV string
|
|
52
|
+
|
|
53
|
+
# Execute query and get pandas DataFrame
|
|
54
|
+
result = connector.execute_query("SELECT * FROM users LIMIT 10", result_format="pandas")
|
|
55
|
+
df = result.sql_return
|
|
56
|
+
print(df.head())
|
|
57
|
+
|
|
58
|
+
# Execute query and get Arrow table
|
|
59
|
+
result = connector.execute_query("SELECT * FROM users LIMIT 10", result_format="arrow")
|
|
60
|
+
arrow_table = result.sql_return
|
|
61
|
+
print(arrow_table.schema)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Metadata Operations
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
# Get databases
|
|
68
|
+
databases = connector.get_databases()
|
|
69
|
+
print(f"Databases: {databases}")
|
|
70
|
+
|
|
71
|
+
# Get schemas
|
|
72
|
+
schemas = connector.get_schemas(database_name="my_database")
|
|
73
|
+
print(f"Schemas: {schemas}")
|
|
74
|
+
|
|
75
|
+
# Get tables
|
|
76
|
+
tables = connector.get_tables(database_name="my_database", schema_name="public")
|
|
77
|
+
print(f"Tables: {tables}")
|
|
78
|
+
|
|
79
|
+
# Get views
|
|
80
|
+
views = connector.get_views(database_name="my_database", schema_name="public")
|
|
81
|
+
print(f"Views: {views}")
|
|
82
|
+
|
|
83
|
+
# Get materialized views
|
|
84
|
+
mvs = connector.get_materialized_views(database_name="my_database", schema_name="public")
|
|
85
|
+
print(f"Materialized Views: {mvs}")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Get Table Schema
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
# Get table structure
|
|
92
|
+
schema = connector.get_schema(
|
|
93
|
+
database_name="my_database",
|
|
94
|
+
schema_name="public",
|
|
95
|
+
table_name="users"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
for column in schema[:-1]: # Last item is table metadata
|
|
99
|
+
print(f"{column['name']}: {column['type']} (nullable: {column['nullable']})")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Get DDL Definitions
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# Get tables with DDL
|
|
106
|
+
tables_with_ddl = connector.get_tables_with_ddl(
|
|
107
|
+
database_name="my_database",
|
|
108
|
+
schema_name="public"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
for table in tables_with_ddl:
|
|
112
|
+
print(f"\nTable: {table['table_name']}")
|
|
113
|
+
print(f"DDL:\n{table['definition']}")
|
|
114
|
+
|
|
115
|
+
# Get views with DDL
|
|
116
|
+
views_with_ddl = connector.get_views_with_ddl(
|
|
117
|
+
database_name="my_database",
|
|
118
|
+
schema_name="public"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Get materialized views with DDL
|
|
122
|
+
mvs_with_ddl = connector.get_materialized_views_with_ddl(
|
|
123
|
+
database_name="my_database",
|
|
124
|
+
schema_name="public"
|
|
125
|
+
)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Get Sample Data
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
# Get sample rows from specific tables
|
|
132
|
+
samples = connector.get_sample_rows(
|
|
133
|
+
tables=["users", "orders"],
|
|
134
|
+
top_n=5,
|
|
135
|
+
database_name="my_database",
|
|
136
|
+
schema_name="public"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
for sample in samples:
|
|
140
|
+
print(f"\nTable: {sample['table_name']}")
|
|
141
|
+
print(sample['sample_rows']) # CSV format
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### CRUD Operations
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
# INSERT
|
|
148
|
+
result = connector.execute_insert(
|
|
149
|
+
"INSERT INTO users (name, email) VALUES ('John', 'john@example.com')"
|
|
150
|
+
)
|
|
151
|
+
print(f"Inserted rows: {result.row_count}")
|
|
152
|
+
|
|
153
|
+
# UPDATE
|
|
154
|
+
result = connector.execute_update(
|
|
155
|
+
"UPDATE users SET email = 'newemail@example.com' WHERE name = 'John'"
|
|
156
|
+
)
|
|
157
|
+
print(f"Updated rows: {result.row_count}")
|
|
158
|
+
|
|
159
|
+
# DELETE
|
|
160
|
+
result = connector.execute_delete(
|
|
161
|
+
"DELETE FROM users WHERE name = 'John'"
|
|
162
|
+
)
|
|
163
|
+
print(f"Deleted rows: {result.row_count}")
|
|
164
|
+
|
|
165
|
+
# DDL
|
|
166
|
+
result = connector.execute_ddl(
|
|
167
|
+
"CREATE TABLE test_table (id INT, name VARCHAR(100))"
|
|
168
|
+
)
|
|
169
|
+
print(f"DDL executed: {result.success}")
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Context Switching
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
# Switch database
|
|
176
|
+
connector.do_switch_context(database_name="another_database")
|
|
177
|
+
|
|
178
|
+
# Switch schema
|
|
179
|
+
connector.do_switch_context(
|
|
180
|
+
database_name="my_database",
|
|
181
|
+
schema_name="another_schema"
|
|
182
|
+
)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Configuration with Datus Agent
|
|
186
|
+
|
|
187
|
+
When using with Datus Agent, the adapter is automatically discovered via entry points:
|
|
188
|
+
|
|
189
|
+
```yaml
|
|
190
|
+
# config.yaml
|
|
191
|
+
database:
|
|
192
|
+
type: snowflake
|
|
193
|
+
account: myaccount
|
|
194
|
+
username: myuser
|
|
195
|
+
password: mypassword
|
|
196
|
+
warehouse: my_warehouse
|
|
197
|
+
database: my_database
|
|
198
|
+
schema: my_schema
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The adapter will be automatically loaded when you use `type: snowflake`.
|
|
202
|
+
|
|
203
|
+
## Architecture
|
|
204
|
+
|
|
205
|
+
This adapter:
|
|
206
|
+
- Inherits from `BaseSqlConnector` in `datus-agent`
|
|
207
|
+
- Uses native Snowflake connector for optimal performance
|
|
208
|
+
- Implements all required abstract methods
|
|
209
|
+
- Provides Snowflake-specific optimizations (SHOW commands, Arrow format)
|
|
210
|
+
|
|
211
|
+
## Development
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# Install in development mode
|
|
215
|
+
cd datus-snowflake
|
|
216
|
+
pip install -e .
|
|
217
|
+
|
|
218
|
+
# Run tests
|
|
219
|
+
pytest tests/
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## License
|
|
223
|
+
|
|
224
|
+
Apache License 2.0
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Snowflake adapter for Datus Agent."""
|
|
2
|
+
|
|
3
|
+
from datus.tools.db_tools import connector_registry
|
|
4
|
+
|
|
5
|
+
from .config import SnowflakeConfig
|
|
6
|
+
from .connector import SnowflakeConnector
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
9
|
+
__all__ = ["SnowflakeConnector", "SnowflakeConfig", "register"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def register():
|
|
13
|
+
"""Register Snowflake connector with Datus registry."""
|
|
14
|
+
connector_registry.register("snowflake", SnowflakeConnector)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# Auto-register when imported
|
|
18
|
+
register()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Copyright 2025-present DatusAI, Inc.
|
|
2
|
+
# Licensed under the Apache License, Version 2.0.
|
|
3
|
+
# See http://www.apache.org/licenses/LICENSE-2.0 for details.
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SnowflakeConfig(BaseModel):
|
|
11
|
+
"""Snowflake-specific configuration."""
|
|
12
|
+
|
|
13
|
+
model_config = ConfigDict(extra="forbid", populate_by_name=True)
|
|
14
|
+
|
|
15
|
+
account: str = Field(..., description="Snowflake account identifier")
|
|
16
|
+
username: str = Field(..., description="Snowflake username")
|
|
17
|
+
password: str = Field(..., description="Snowflake password")
|
|
18
|
+
warehouse: str = Field(..., description="Snowflake warehouse name")
|
|
19
|
+
database: Optional[str] = Field(default=None, description="Default database name")
|
|
20
|
+
schema_name: Optional[str] = Field(default=None, alias="schema", description="Default schema name")
|
|
21
|
+
role: Optional[str] = Field(default=None, description="Snowflake role to use")
|
|
22
|
+
timeout_seconds: int = Field(default=30, description="Connection timeout in seconds")
|