mcp-dbutils 0.4.0__tar.gz → 0.5.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.
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/CHANGELOG.md +24 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/PKG-INFO +13 -2
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/README.md +12 -1
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/README_CN.md +12 -1
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/config.yaml.example +11 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/pyproject.toml +1 -1
- mcp_dbutils-0.5.0/src/mcp_dbutils/sqlite/config.py +150 -0
- mcp_dbutils-0.5.0/tests/integration/test_sqlite_config.py +109 -0
- mcp_dbutils-0.4.0/src/mcp_dbutils/sqlite/config.py +0 -74
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/.coveragerc +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/.github/workflows/release.yml +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/.github/workflows/test.yml +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/.gitignore +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/Dockerfile +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/LICENSE +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/smithery.yaml +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/src/mcp_dbutils/__init__.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/src/mcp_dbutils/base.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/src/mcp_dbutils/config.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/src/mcp_dbutils/log.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/src/mcp_dbutils/postgres/__init__.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/src/mcp_dbutils/postgres/config.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/src/mcp_dbutils/postgres/handler.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/src/mcp_dbutils/postgres/server.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/src/mcp_dbutils/sqlite/__init__.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/src/mcp_dbutils/sqlite/handler.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/src/mcp_dbutils/sqlite/server.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/src/mcp_dbutils/stats.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/tests/conftest.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/tests/integration/test_monitoring.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/tests/integration/test_postgres.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/tests/integration/test_postgres_config.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/tests/integration/test_prompts.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/tests/integration/test_sqlite.py +0 -0
- {mcp_dbutils-0.4.0 → mcp_dbutils-0.5.0}/tests/unit/test_stats.py +0 -0
@@ -1,6 +1,30 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
3
|
|
4
|
+
## v0.5.0 (2025-03-02)
|
5
|
+
|
6
|
+
### Documentation
|
7
|
+
|
8
|
+
- Add JDBC URL configuration documentation
|
9
|
+
([`a1b5f4b`](https://github.com/donghao1393/mcp-dbutils/commit/a1b5f4b424cec0df239bed65705aaac7c3e9072a))
|
10
|
+
|
11
|
+
- Add JDBC URL configuration examples to English and Chinese docs - Document secure credential
|
12
|
+
handling approach - Update configuration format descriptions
|
13
|
+
|
14
|
+
Part of feature #2
|
15
|
+
|
16
|
+
### Features
|
17
|
+
|
18
|
+
- **config**: Add JDBC URL support for SQLite
|
19
|
+
([#5](https://github.com/donghao1393/mcp-dbutils/pull/5),
|
20
|
+
[`9feb1e8`](https://github.com/donghao1393/mcp-dbutils/commit/9feb1e8c7e38a8e4e3c0f63c81a72f4a4edd05b5))
|
21
|
+
|
22
|
+
- Add JDBC URL parsing for SQLite configuration - Support SQLite specific URL format and parameters
|
23
|
+
- Keep credentials separate from URL - Complete test coverage for new functionality
|
24
|
+
|
25
|
+
Part of #4
|
26
|
+
|
27
|
+
|
4
28
|
## v0.4.0 (2025-03-01)
|
5
29
|
|
6
30
|
### Features
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: mcp-dbutils
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.5.0
|
4
4
|
Summary: MCP Database Utilities Service
|
5
5
|
Author: Dong Hao
|
6
6
|
License-Expression: MIT
|
@@ -148,7 +148,7 @@ The project requires a YAML configuration file, specified via the `--config` par
|
|
148
148
|
|
149
149
|
```yaml
|
150
150
|
databases:
|
151
|
-
# PostgreSQL example
|
151
|
+
# Standard PostgreSQL configuration example
|
152
152
|
my_postgres:
|
153
153
|
type: postgres
|
154
154
|
dbname: test_db
|
@@ -158,6 +158,13 @@ databases:
|
|
158
158
|
# host: 172.17.0.1 # For Linux (docker0 IP)
|
159
159
|
port: 5432
|
160
160
|
|
161
|
+
# PostgreSQL with JDBC URL example
|
162
|
+
my_postgres_jdbc:
|
163
|
+
type: postgres
|
164
|
+
jdbc_url: jdbc:postgresql://host.docker.internal:5432/test_db
|
165
|
+
user: postgres # Credentials must be provided separately
|
166
|
+
password: secret # Not included in JDBC URL for security
|
167
|
+
|
161
168
|
# SQLite example (when using Docker)
|
162
169
|
my_sqlite:
|
163
170
|
type: sqlite
|
@@ -165,6 +172,10 @@ databases:
|
|
165
172
|
password: optional_password # optional
|
166
173
|
```
|
167
174
|
|
175
|
+
The configuration supports two formats for PostgreSQL:
|
176
|
+
1. Standard configuration with individual parameters
|
177
|
+
2. JDBC URL configuration with separate credentials (recommended for better compatibility)
|
178
|
+
|
168
179
|
### Debug Mode
|
169
180
|
Set environment variable `MCP_DEBUG=1` to enable debug mode for detailed logging output.
|
170
181
|
|
@@ -126,7 +126,7 @@ The project requires a YAML configuration file, specified via the `--config` par
|
|
126
126
|
|
127
127
|
```yaml
|
128
128
|
databases:
|
129
|
-
# PostgreSQL example
|
129
|
+
# Standard PostgreSQL configuration example
|
130
130
|
my_postgres:
|
131
131
|
type: postgres
|
132
132
|
dbname: test_db
|
@@ -136,6 +136,13 @@ databases:
|
|
136
136
|
# host: 172.17.0.1 # For Linux (docker0 IP)
|
137
137
|
port: 5432
|
138
138
|
|
139
|
+
# PostgreSQL with JDBC URL example
|
140
|
+
my_postgres_jdbc:
|
141
|
+
type: postgres
|
142
|
+
jdbc_url: jdbc:postgresql://host.docker.internal:5432/test_db
|
143
|
+
user: postgres # Credentials must be provided separately
|
144
|
+
password: secret # Not included in JDBC URL for security
|
145
|
+
|
139
146
|
# SQLite example (when using Docker)
|
140
147
|
my_sqlite:
|
141
148
|
type: sqlite
|
@@ -143,6 +150,10 @@ databases:
|
|
143
150
|
password: optional_password # optional
|
144
151
|
```
|
145
152
|
|
153
|
+
The configuration supports two formats for PostgreSQL:
|
154
|
+
1. Standard configuration with individual parameters
|
155
|
+
2. JDBC URL configuration with separate credentials (recommended for better compatibility)
|
156
|
+
|
146
157
|
### Debug Mode
|
147
158
|
Set environment variable `MCP_DEBUG=1` to enable debug mode for detailed logging output.
|
148
159
|
|
@@ -110,7 +110,7 @@ docker run -i --rm \
|
|
110
110
|
|
111
111
|
```yaml
|
112
112
|
databases:
|
113
|
-
# PostgreSQL
|
113
|
+
# PostgreSQL标准配置示例
|
114
114
|
my_postgres:
|
115
115
|
type: postgres
|
116
116
|
dbname: test_db
|
@@ -120,6 +120,13 @@ databases:
|
|
120
120
|
# host: 172.17.0.1 # Linux系统使用(docker0网络IP)
|
121
121
|
port: 5432
|
122
122
|
|
123
|
+
# PostgreSQL JDBC URL配置示例
|
124
|
+
my_postgres_jdbc:
|
125
|
+
type: postgres
|
126
|
+
jdbc_url: jdbc:postgresql://host.docker.internal:5432/test_db
|
127
|
+
user: postgres # 认证信息必须单独提供
|
128
|
+
password: secret # 出于安全考虑,不包含在JDBC URL中
|
129
|
+
|
123
130
|
# SQLite配置示例(使用Docker)
|
124
131
|
my_sqlite:
|
125
132
|
type: sqlite
|
@@ -127,6 +134,10 @@ databases:
|
|
127
134
|
password: optional_password # 可选
|
128
135
|
```
|
129
136
|
|
137
|
+
PostgreSQL配置支持两种格式:
|
138
|
+
1. 标准配置:使用独立的参数配置
|
139
|
+
2. JDBC URL配置:使用JDBC URL并单独提供认证信息(推荐,兼容性更好)
|
140
|
+
|
130
141
|
### 调试模式
|
131
142
|
设置环境变量 `MCP_DEBUG=1` 启用调试模式,可以看到详细的日志输出。
|
132
143
|
|
@@ -1,10 +1,21 @@
|
|
1
1
|
databases:
|
2
2
|
# SQLite configuration examples
|
3
|
+
# SQLite with standard configuration
|
3
4
|
dev-db:
|
4
5
|
type: sqlite
|
5
6
|
path: /path/to/dev.db
|
6
7
|
password:
|
7
8
|
|
9
|
+
# SQLite with JDBC URL configuration
|
10
|
+
# jdbc:sqlite: URL supports query parameters:
|
11
|
+
# - mode=ro: Read-only mode
|
12
|
+
# - cache=shared: Shared cache mode
|
13
|
+
# Note: Password must be provided separately
|
14
|
+
prod-sqlite:
|
15
|
+
type: sqlite
|
16
|
+
jdbc_url: jdbc:sqlite:/path/to/prod.db?mode=ro
|
17
|
+
password: optional_password # Provided separately for security
|
18
|
+
|
8
19
|
# PostgreSQL configuration examples
|
9
20
|
# Standard configuration
|
10
21
|
test-db:
|
@@ -0,0 +1,150 @@
|
|
1
|
+
"""SQLite configuration module"""
|
2
|
+
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import Dict, Any, Optional, Literal
|
6
|
+
from urllib.parse import urlparse, parse_qs
|
7
|
+
from ..config import DatabaseConfig
|
8
|
+
|
9
|
+
def parse_jdbc_url(jdbc_url: str) -> Dict[str, str]:
|
10
|
+
"""Parse JDBC URL into connection parameters
|
11
|
+
|
12
|
+
Args:
|
13
|
+
jdbc_url: JDBC URL (e.g. jdbc:sqlite:file:/path/to/database.db or jdbc:sqlite:/path/to/database.db)
|
14
|
+
|
15
|
+
Returns:
|
16
|
+
Dictionary of connection parameters
|
17
|
+
|
18
|
+
Raises:
|
19
|
+
ValueError: If URL format is invalid
|
20
|
+
"""
|
21
|
+
if not jdbc_url.startswith('jdbc:sqlite:'):
|
22
|
+
raise ValueError("Invalid SQLite JDBC URL format")
|
23
|
+
|
24
|
+
# Remove jdbc:sqlite: prefix
|
25
|
+
url = jdbc_url[12:]
|
26
|
+
|
27
|
+
# Handle file: prefix
|
28
|
+
if url.startswith('file:'):
|
29
|
+
url = url[5:]
|
30
|
+
|
31
|
+
# Parse URL
|
32
|
+
parsed = urlparse(url)
|
33
|
+
path = parsed.path
|
34
|
+
|
35
|
+
# Extract query parameters
|
36
|
+
params = {}
|
37
|
+
if parsed.query:
|
38
|
+
query_params = parse_qs(parsed.query)
|
39
|
+
for key, values in query_params.items():
|
40
|
+
params[key] = values[0]
|
41
|
+
|
42
|
+
if not path:
|
43
|
+
raise ValueError("Database path must be specified in URL")
|
44
|
+
|
45
|
+
return {
|
46
|
+
'path': path,
|
47
|
+
'parameters': params
|
48
|
+
}
|
49
|
+
|
50
|
+
@dataclass
|
51
|
+
class SqliteConfig(DatabaseConfig):
|
52
|
+
path: str
|
53
|
+
password: Optional[str] = None
|
54
|
+
uri: bool = True # Enable URI mode to support parameters like password
|
55
|
+
type: Literal['sqlite'] = 'sqlite'
|
56
|
+
|
57
|
+
@classmethod
|
58
|
+
def from_jdbc_url(cls, jdbc_url: str, password: Optional[str] = None) -> 'SqliteConfig':
|
59
|
+
"""Create configuration from JDBC URL
|
60
|
+
|
61
|
+
Args:
|
62
|
+
jdbc_url: JDBC URL (e.g. jdbc:sqlite:file:/path/to/database.db)
|
63
|
+
password: Optional password for database encryption
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
SqliteConfig instance
|
67
|
+
|
68
|
+
Raises:
|
69
|
+
ValueError: If URL format is invalid
|
70
|
+
"""
|
71
|
+
params = parse_jdbc_url(jdbc_url)
|
72
|
+
|
73
|
+
config = cls(
|
74
|
+
path=params['path'],
|
75
|
+
password=password,
|
76
|
+
uri=True
|
77
|
+
)
|
78
|
+
config.debug = cls.get_debug_mode()
|
79
|
+
return config
|
80
|
+
|
81
|
+
@property
|
82
|
+
def absolute_path(self) -> str:
|
83
|
+
"""Return absolute path to database file"""
|
84
|
+
return str(Path(self.path).expanduser().resolve())
|
85
|
+
|
86
|
+
def get_connection_params(self) -> Dict[str, Any]:
|
87
|
+
"""Get sqlite3 connection parameters"""
|
88
|
+
if not self.password:
|
89
|
+
return {'database': self.absolute_path, 'uri': self.uri}
|
90
|
+
|
91
|
+
# Use URI format if password is provided
|
92
|
+
uri = f"file:{self.absolute_path}?mode=rw"
|
93
|
+
if self.password:
|
94
|
+
uri += f"&password={self.password}"
|
95
|
+
|
96
|
+
return {
|
97
|
+
'database': uri,
|
98
|
+
'uri': True
|
99
|
+
}
|
100
|
+
|
101
|
+
def get_masked_connection_info(self) -> Dict[str, Any]:
|
102
|
+
"""Return connection information for logging"""
|
103
|
+
info = {
|
104
|
+
'database': self.absolute_path,
|
105
|
+
'uri': self.uri
|
106
|
+
}
|
107
|
+
if self.password:
|
108
|
+
info['password'] = '******'
|
109
|
+
return info
|
110
|
+
|
111
|
+
@classmethod
|
112
|
+
def from_yaml(cls, yaml_path: str, db_name: str, **kwargs) -> 'SqliteConfig':
|
113
|
+
"""Create SQLite configuration from YAML
|
114
|
+
|
115
|
+
Args:
|
116
|
+
yaml_path: Path to YAML configuration file
|
117
|
+
db_name: Database configuration name
|
118
|
+
"""
|
119
|
+
configs = cls.load_yaml_config(yaml_path)
|
120
|
+
|
121
|
+
if db_name not in configs:
|
122
|
+
available_dbs = list(configs.keys())
|
123
|
+
raise ValueError(f"Database configuration not found: {db_name}. Available configurations: {available_dbs}")
|
124
|
+
|
125
|
+
db_config = configs[db_name]
|
126
|
+
|
127
|
+
if 'type' not in db_config:
|
128
|
+
raise ValueError("Database configuration must include 'type' field")
|
129
|
+
if db_config['type'] != 'sqlite':
|
130
|
+
raise ValueError(f"Configuration is not SQLite type: {db_config['type']}")
|
131
|
+
|
132
|
+
# Check if using JDBC URL configuration
|
133
|
+
if 'jdbc_url' in db_config:
|
134
|
+
params = parse_jdbc_url(db_config['jdbc_url'])
|
135
|
+
config = cls(
|
136
|
+
path=params['path'],
|
137
|
+
password=db_config.get('password'),
|
138
|
+
uri=True
|
139
|
+
)
|
140
|
+
else:
|
141
|
+
if 'path' not in db_config:
|
142
|
+
raise ValueError("SQLite configuration must include 'path' field")
|
143
|
+
config = cls(
|
144
|
+
path=db_config['path'],
|
145
|
+
password=db_config.get('password'),
|
146
|
+
uri=True
|
147
|
+
)
|
148
|
+
|
149
|
+
config.debug = cls.get_debug_mode()
|
150
|
+
return config
|
@@ -0,0 +1,109 @@
|
|
1
|
+
"""Test SQLite configuration functionality"""
|
2
|
+
import pytest
|
3
|
+
import tempfile
|
4
|
+
import yaml
|
5
|
+
from pathlib import Path
|
6
|
+
from mcp_dbutils.sqlite.config import SqliteConfig, parse_jdbc_url
|
7
|
+
|
8
|
+
def test_parse_jdbc_url():
|
9
|
+
"""Test JDBC URL parsing"""
|
10
|
+
# Test basic URL
|
11
|
+
url = "jdbc:sqlite:/path/to/test.db"
|
12
|
+
params = parse_jdbc_url(url)
|
13
|
+
assert params["path"] == "/path/to/test.db"
|
14
|
+
assert params["parameters"] == {}
|
15
|
+
|
16
|
+
# Test URL with file: prefix
|
17
|
+
url = "jdbc:sqlite:file:/path/to/test.db"
|
18
|
+
params = parse_jdbc_url(url)
|
19
|
+
assert params["path"] == "/path/to/test.db"
|
20
|
+
assert params["parameters"] == {}
|
21
|
+
|
22
|
+
# Test URL with parameters
|
23
|
+
url = "jdbc:sqlite:/path/to/test.db?mode=ro&cache=shared"
|
24
|
+
params = parse_jdbc_url(url)
|
25
|
+
assert params["path"] == "/path/to/test.db"
|
26
|
+
assert params["parameters"] == {"mode": "ro", "cache": "shared"}
|
27
|
+
|
28
|
+
# Test invalid format
|
29
|
+
with pytest.raises(ValueError, match="Invalid SQLite JDBC URL format"):
|
30
|
+
parse_jdbc_url("sqlite:/path/to/test.db")
|
31
|
+
|
32
|
+
# Test missing path
|
33
|
+
with pytest.raises(ValueError, match="Database path must be specified"):
|
34
|
+
parse_jdbc_url("jdbc:sqlite:")
|
35
|
+
|
36
|
+
def test_from_jdbc_url():
|
37
|
+
"""Test SqliteConfig creation from JDBC URL"""
|
38
|
+
url = "jdbc:sqlite:/path/to/test.db"
|
39
|
+
config = SqliteConfig.from_jdbc_url(url)
|
40
|
+
|
41
|
+
assert str(Path(config.path)) == str(Path("/path/to/test.db"))
|
42
|
+
assert config.password is None
|
43
|
+
assert config.uri is True
|
44
|
+
assert config.type == "sqlite"
|
45
|
+
|
46
|
+
# Test with password
|
47
|
+
config = SqliteConfig.from_jdbc_url(url, password="test_pass")
|
48
|
+
assert config.password == "test_pass"
|
49
|
+
assert config.uri is True
|
50
|
+
|
51
|
+
def test_from_yaml_with_jdbc_url(tmp_path):
|
52
|
+
"""Test SqliteConfig creation from YAML with JDBC URL"""
|
53
|
+
config_data = {
|
54
|
+
"databases": {
|
55
|
+
"test_db": {
|
56
|
+
"type": "sqlite",
|
57
|
+
"jdbc_url": "jdbc:sqlite:/path/to/test.db",
|
58
|
+
"password": "test_pass"
|
59
|
+
}
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
config_file = tmp_path / "config.yaml"
|
64
|
+
with open(config_file, "w") as f:
|
65
|
+
yaml.dump(config_data, f)
|
66
|
+
|
67
|
+
config = SqliteConfig.from_yaml(str(config_file), "test_db")
|
68
|
+
assert str(Path(config.path)) == str(Path("/path/to/test.db"))
|
69
|
+
assert config.password == "test_pass"
|
70
|
+
assert config.uri is True
|
71
|
+
assert config.type == "sqlite"
|
72
|
+
|
73
|
+
def test_required_fields_validation(tmp_path):
|
74
|
+
"""Test validation of required configuration fields"""
|
75
|
+
# Missing type
|
76
|
+
config_data = {
|
77
|
+
"databases": {
|
78
|
+
"test_db": {
|
79
|
+
"jdbc_url": "jdbc:sqlite:/path/to/test.db"
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
config_file = tmp_path / "config.yaml"
|
85
|
+
with open(config_file, "w") as f:
|
86
|
+
yaml.dump(config_data, f)
|
87
|
+
|
88
|
+
with pytest.raises(ValueError, match="missing required 'type' field"):
|
89
|
+
SqliteConfig.from_yaml(str(config_file), "test_db")
|
90
|
+
|
91
|
+
# Wrong type
|
92
|
+
config_data["databases"]["test_db"]["type"] = "postgres"
|
93
|
+
|
94
|
+
with open(config_file, "w") as f:
|
95
|
+
yaml.dump(config_data, f)
|
96
|
+
|
97
|
+
with pytest.raises(ValueError, match="Configuration is not SQLite type"):
|
98
|
+
SqliteConfig.from_yaml(str(config_file), "test_db")
|
99
|
+
|
100
|
+
# Standard config (non-JDBC) missing path
|
101
|
+
config_data["databases"]["test_db"] = {
|
102
|
+
"type": "sqlite"
|
103
|
+
}
|
104
|
+
|
105
|
+
with open(config_file, "w") as f:
|
106
|
+
yaml.dump(config_data, f)
|
107
|
+
|
108
|
+
with pytest.raises(ValueError, match="must include 'path' field"):
|
109
|
+
SqliteConfig.from_yaml(str(config_file), "test_db")
|
@@ -1,74 +0,0 @@
|
|
1
|
-
"""SQLite configuration module"""
|
2
|
-
|
3
|
-
from dataclasses import dataclass
|
4
|
-
from pathlib import Path
|
5
|
-
from typing import Dict, Any, Optional, Literal
|
6
|
-
from ..config import DatabaseConfig
|
7
|
-
|
8
|
-
@dataclass
|
9
|
-
class SqliteConfig(DatabaseConfig):
|
10
|
-
path: str
|
11
|
-
password: Optional[str] = None
|
12
|
-
uri: bool = True # Enable URI mode to support parameters like password
|
13
|
-
type: Literal['sqlite'] = 'sqlite'
|
14
|
-
|
15
|
-
@property
|
16
|
-
def absolute_path(self) -> str:
|
17
|
-
"""Return absolute path to database file"""
|
18
|
-
return str(Path(self.path).expanduser().resolve())
|
19
|
-
|
20
|
-
def get_connection_params(self) -> Dict[str, Any]:
|
21
|
-
"""Get sqlite3 connection parameters"""
|
22
|
-
if not self.password:
|
23
|
-
return {'database': self.absolute_path, 'uri': self.uri}
|
24
|
-
|
25
|
-
# Use URI format if password is provided
|
26
|
-
uri = f"file:{self.absolute_path}?mode=rw"
|
27
|
-
if self.password:
|
28
|
-
uri += f"&password={self.password}"
|
29
|
-
|
30
|
-
return {
|
31
|
-
'database': uri,
|
32
|
-
'uri': True
|
33
|
-
}
|
34
|
-
|
35
|
-
def get_masked_connection_info(self) -> Dict[str, Any]:
|
36
|
-
"""Return connection information for logging"""
|
37
|
-
info = {
|
38
|
-
'database': self.absolute_path,
|
39
|
-
'uri': self.uri
|
40
|
-
}
|
41
|
-
if self.password:
|
42
|
-
info['password'] = '******'
|
43
|
-
return info
|
44
|
-
|
45
|
-
@classmethod
|
46
|
-
def from_yaml(cls, yaml_path: str, db_name: str, **kwargs) -> 'SqliteConfig':
|
47
|
-
"""Create SQLite configuration from YAML
|
48
|
-
|
49
|
-
Args:
|
50
|
-
yaml_path: Path to YAML configuration file
|
51
|
-
db_name: Database configuration name
|
52
|
-
"""
|
53
|
-
configs = cls.load_yaml_config(yaml_path)
|
54
|
-
|
55
|
-
if db_name not in configs:
|
56
|
-
available_dbs = list(configs.keys())
|
57
|
-
raise ValueError(f"Database configuration not found: {db_name}. Available configurations: {available_dbs}")
|
58
|
-
|
59
|
-
db_config = configs[db_name]
|
60
|
-
|
61
|
-
if 'type' not in db_config:
|
62
|
-
raise ValueError("Database configuration must include 'type' field")
|
63
|
-
if db_config['type'] != 'sqlite':
|
64
|
-
raise ValueError(f"Configuration is not SQLite type: {db_config['type']}")
|
65
|
-
if 'path' not in db_config:
|
66
|
-
raise ValueError("SQLite configuration must include 'path' field")
|
67
|
-
|
68
|
-
config = cls(
|
69
|
-
path=db_config['path'],
|
70
|
-
password=db_config.get('password'),
|
71
|
-
uri=True
|
72
|
-
)
|
73
|
-
config.debug = cls.get_debug_mode()
|
74
|
-
return config
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|