ddcdatabases 4.0.0__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.
- ddcdatabases/.env.example +200 -0
- ddcdatabases/__init__.py +203 -0
- ddcdatabases/core/__init__.py +0 -0
- ddcdatabases/core/base.py +192 -0
- ddcdatabases/core/configs.py +128 -0
- ddcdatabases/core/constants.py +118 -0
- ddcdatabases/core/exceptions.py +43 -0
- ddcdatabases/core/operations.py +381 -0
- ddcdatabases/core/persistent.py +1292 -0
- ddcdatabases/core/retry.py +182 -0
- ddcdatabases/core/settings.py +279 -0
- ddcdatabases/mongodb.py +325 -0
- ddcdatabases/mssql.py +193 -0
- ddcdatabases/mysql.py +196 -0
- ddcdatabases/oracle.py +178 -0
- ddcdatabases/postgresql.py +265 -0
- ddcdatabases/sqlite.py +128 -0
- ddcdatabases-4.0.0.dist-info/METADATA +788 -0
- ddcdatabases-4.0.0.dist-info/RECORD +21 -0
- ddcdatabases-4.0.0.dist-info/WHEEL +4 -0
- ddcdatabases-4.0.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# ddcdatabases Environment Variables Example
|
|
2
|
+
# Copy this file to .env and adjust values as needed
|
|
3
|
+
|
|
4
|
+
# SQLite Database Settings
|
|
5
|
+
SQLITE_FILE_PATH=sqlite.db
|
|
6
|
+
SQLITE_ECHO=false
|
|
7
|
+
# Connection Retry settings
|
|
8
|
+
SQLITE_CONNECTION_ENABLE_RETRY=false
|
|
9
|
+
SQLITE_CONNECTION_MAX_RETRIES=1
|
|
10
|
+
SQLITE_CONNECTION_INITIAL_RETRY_DELAY=1.0
|
|
11
|
+
SQLITE_CONNECTION_MAX_RETRY_DELAY=30.0
|
|
12
|
+
# Operation Retry settings
|
|
13
|
+
SQLITE_OPERATION_ENABLE_RETRY=false
|
|
14
|
+
SQLITE_OPERATION_MAX_RETRIES=1
|
|
15
|
+
SQLITE_OPERATION_INITIAL_RETRY_DELAY=0.5
|
|
16
|
+
SQLITE_OPERATION_MAX_RETRY_DELAY=10.0
|
|
17
|
+
SQLITE_OPERATION_JITTER=0.1
|
|
18
|
+
|
|
19
|
+
# PostgreSQL Database Settings
|
|
20
|
+
POSTGRESQL_HOST=localhost
|
|
21
|
+
POSTGRESQL_PORT=5432
|
|
22
|
+
POSTGRESQL_USER=postgres
|
|
23
|
+
POSTGRESQL_PASSWORD=password
|
|
24
|
+
POSTGRESQL_DATABASE=postgres
|
|
25
|
+
# Comma-separated for multiple schemas (e.g. public,schema2)
|
|
26
|
+
POSTGRESQL_SCHEMA=public
|
|
27
|
+
# Session settings
|
|
28
|
+
POSTGRESQL_ECHO=false
|
|
29
|
+
POSTGRESQL_AUTOFLUSH=false
|
|
30
|
+
POSTGRESQL_EXPIRE_ON_COMMIT=false
|
|
31
|
+
POSTGRESQL_AUTOCOMMIT=false
|
|
32
|
+
# Pool settings
|
|
33
|
+
POSTGRESQL_CONNECTION_TIMEOUT=30
|
|
34
|
+
POSTGRESQL_POOL_RECYCLE=3600
|
|
35
|
+
POSTGRESQL_POOL_SIZE=25
|
|
36
|
+
POSTGRESQL_MAX_OVERFLOW=50
|
|
37
|
+
# SSL settings
|
|
38
|
+
POSTGRESQL_SSL_MODE=disable
|
|
39
|
+
POSTGRESQL_SSL_CA_CERT_PATH=
|
|
40
|
+
POSTGRESQL_SSL_CLIENT_CERT_PATH=
|
|
41
|
+
POSTGRESQL_SSL_CLIENT_KEY_PATH=
|
|
42
|
+
# Connection Retry settings
|
|
43
|
+
POSTGRESQL_CONNECTION_ENABLE_RETRY=true
|
|
44
|
+
POSTGRESQL_CONNECTION_MAX_RETRIES=3
|
|
45
|
+
POSTGRESQL_CONNECTION_INITIAL_RETRY_DELAY=1.0
|
|
46
|
+
POSTGRESQL_CONNECTION_MAX_RETRY_DELAY=30.0
|
|
47
|
+
POSTGRESQL_CONNECTION_DISCONNECT_IDLE_TIMEOUT=300
|
|
48
|
+
# Operation Retry settings
|
|
49
|
+
POSTGRESQL_OPERATION_ENABLE_RETRY=true
|
|
50
|
+
POSTGRESQL_OPERATION_MAX_RETRIES=3
|
|
51
|
+
POSTGRESQL_OPERATION_INITIAL_RETRY_DELAY=0.5
|
|
52
|
+
POSTGRESQL_OPERATION_MAX_RETRY_DELAY=10.0
|
|
53
|
+
POSTGRESQL_OPERATION_JITTER=0.1
|
|
54
|
+
# Persistent connection settings
|
|
55
|
+
POSTGRESQL_PERSISTENT_IDLE_TIMEOUT=300
|
|
56
|
+
POSTGRESQL_PERSISTENT_HEALTH_CHECK_INTERVAL=30
|
|
57
|
+
POSTGRESQL_PERSISTENT_AUTO_RECONNECT=true
|
|
58
|
+
|
|
59
|
+
# Microsoft SQL Server Database Settings
|
|
60
|
+
MSSQL_HOST=localhost
|
|
61
|
+
MSSQL_PORT=1433
|
|
62
|
+
MSSQL_USER=sa
|
|
63
|
+
MSSQL_PASSWORD=password
|
|
64
|
+
MSSQL_DATABASE=master
|
|
65
|
+
MSSQL_SCHEMA=dbo
|
|
66
|
+
# Session settings
|
|
67
|
+
MSSQL_ECHO=false
|
|
68
|
+
MSSQL_AUTOFLUSH=false
|
|
69
|
+
MSSQL_EXPIRE_ON_COMMIT=false
|
|
70
|
+
MSSQL_AUTOCOMMIT=false
|
|
71
|
+
# Pool settings
|
|
72
|
+
MSSQL_CONNECTION_TIMEOUT=30
|
|
73
|
+
MSSQL_POOL_RECYCLE=3600
|
|
74
|
+
MSSQL_POOL_SIZE=25
|
|
75
|
+
MSSQL_MAX_OVERFLOW=50
|
|
76
|
+
MSSQL_ODBCDRIVER_VERSION=18
|
|
77
|
+
# SSL settings
|
|
78
|
+
MSSQL_SSL_ENCRYPT=false
|
|
79
|
+
MSSQL_SSL_TRUST_SERVER_CERTIFICATE=true
|
|
80
|
+
MSSQL_SSL_CA_CERT_PATH=
|
|
81
|
+
# Connection Retry settings
|
|
82
|
+
MSSQL_CONNECTION_ENABLE_RETRY=true
|
|
83
|
+
MSSQL_CONNECTION_MAX_RETRIES=3
|
|
84
|
+
MSSQL_CONNECTION_INITIAL_RETRY_DELAY=1.0
|
|
85
|
+
MSSQL_CONNECTION_MAX_RETRY_DELAY=30.0
|
|
86
|
+
MSSQL_CONNECTION_DISCONNECT_IDLE_TIMEOUT=300
|
|
87
|
+
# Operation Retry settings
|
|
88
|
+
MSSQL_OPERATION_ENABLE_RETRY=true
|
|
89
|
+
MSSQL_OPERATION_MAX_RETRIES=3
|
|
90
|
+
MSSQL_OPERATION_INITIAL_RETRY_DELAY=0.5
|
|
91
|
+
MSSQL_OPERATION_MAX_RETRY_DELAY=10.0
|
|
92
|
+
MSSQL_OPERATION_JITTER=0.1
|
|
93
|
+
# Persistent connection settings
|
|
94
|
+
MSSQL_PERSISTENT_IDLE_TIMEOUT=300
|
|
95
|
+
MSSQL_PERSISTENT_HEALTH_CHECK_INTERVAL=30
|
|
96
|
+
MSSQL_PERSISTENT_AUTO_RECONNECT=true
|
|
97
|
+
|
|
98
|
+
# MySQL Database Settings
|
|
99
|
+
MYSQL_HOST=localhost
|
|
100
|
+
MYSQL_PORT=3306
|
|
101
|
+
MYSQL_USER=root
|
|
102
|
+
MYSQL_PASSWORD=password
|
|
103
|
+
MYSQL_DATABASE=dev
|
|
104
|
+
# Session settings
|
|
105
|
+
MYSQL_ECHO=false
|
|
106
|
+
MYSQL_AUTOFLUSH=false
|
|
107
|
+
MYSQL_EXPIRE_ON_COMMIT=false
|
|
108
|
+
MYSQL_AUTOCOMMIT=true
|
|
109
|
+
# Pool settings
|
|
110
|
+
MYSQL_CONNECTION_TIMEOUT=30
|
|
111
|
+
MYSQL_POOL_RECYCLE=3600
|
|
112
|
+
MYSQL_POOL_SIZE=10
|
|
113
|
+
MYSQL_MAX_OVERFLOW=20
|
|
114
|
+
# SSL settings
|
|
115
|
+
MYSQL_SSL_MODE=DISABLED
|
|
116
|
+
MYSQL_SSL_CA_CERT_PATH=
|
|
117
|
+
MYSQL_SSL_CLIENT_CERT_PATH=
|
|
118
|
+
MYSQL_SSL_CLIENT_KEY_PATH=
|
|
119
|
+
# Connection Retry settings
|
|
120
|
+
MYSQL_CONNECTION_ENABLE_RETRY=true
|
|
121
|
+
MYSQL_CONNECTION_MAX_RETRIES=3
|
|
122
|
+
MYSQL_CONNECTION_INITIAL_RETRY_DELAY=1.0
|
|
123
|
+
MYSQL_CONNECTION_MAX_RETRY_DELAY=30.0
|
|
124
|
+
MYSQL_CONNECTION_DISCONNECT_IDLE_TIMEOUT=300
|
|
125
|
+
# Operation Retry settings
|
|
126
|
+
MYSQL_OPERATION_ENABLE_RETRY=true
|
|
127
|
+
MYSQL_OPERATION_MAX_RETRIES=3
|
|
128
|
+
MYSQL_OPERATION_INITIAL_RETRY_DELAY=0.5
|
|
129
|
+
MYSQL_OPERATION_MAX_RETRY_DELAY=10.0
|
|
130
|
+
MYSQL_OPERATION_JITTER=0.1
|
|
131
|
+
# Persistent connection settings
|
|
132
|
+
MYSQL_PERSISTENT_IDLE_TIMEOUT=300
|
|
133
|
+
MYSQL_PERSISTENT_HEALTH_CHECK_INTERVAL=30
|
|
134
|
+
MYSQL_PERSISTENT_AUTO_RECONNECT=true
|
|
135
|
+
|
|
136
|
+
# Oracle Database Settings
|
|
137
|
+
ORACLE_HOST=localhost
|
|
138
|
+
ORACLE_PORT=1521
|
|
139
|
+
ORACLE_USER=system
|
|
140
|
+
ORACLE_PASSWORD=oracle
|
|
141
|
+
ORACLE_SERVICENAME=xe
|
|
142
|
+
# Session settings
|
|
143
|
+
ORACLE_ECHO=false
|
|
144
|
+
ORACLE_AUTOFLUSH=false
|
|
145
|
+
ORACLE_EXPIRE_ON_COMMIT=false
|
|
146
|
+
ORACLE_AUTOCOMMIT=false
|
|
147
|
+
# Pool settings
|
|
148
|
+
ORACLE_CONNECTION_TIMEOUT=30
|
|
149
|
+
ORACLE_POOL_RECYCLE=3600
|
|
150
|
+
ORACLE_POOL_SIZE=10
|
|
151
|
+
ORACLE_MAX_OVERFLOW=20
|
|
152
|
+
# SSL settings
|
|
153
|
+
ORACLE_SSL_ENABLED=false
|
|
154
|
+
ORACLE_SSL_WALLET_PATH=
|
|
155
|
+
# Connection Retry settings
|
|
156
|
+
ORACLE_CONNECTION_ENABLE_RETRY=true
|
|
157
|
+
ORACLE_CONNECTION_MAX_RETRIES=3
|
|
158
|
+
ORACLE_CONNECTION_INITIAL_RETRY_DELAY=1.0
|
|
159
|
+
ORACLE_CONNECTION_MAX_RETRY_DELAY=30.0
|
|
160
|
+
ORACLE_CONNECTION_DISCONNECT_IDLE_TIMEOUT=300
|
|
161
|
+
# Operation Retry settings
|
|
162
|
+
ORACLE_OPERATION_ENABLE_RETRY=true
|
|
163
|
+
ORACLE_OPERATION_MAX_RETRIES=3
|
|
164
|
+
ORACLE_OPERATION_INITIAL_RETRY_DELAY=0.5
|
|
165
|
+
ORACLE_OPERATION_MAX_RETRY_DELAY=10.0
|
|
166
|
+
ORACLE_OPERATION_JITTER=0.1
|
|
167
|
+
# Persistent connection settings
|
|
168
|
+
ORACLE_PERSISTENT_IDLE_TIMEOUT=300
|
|
169
|
+
ORACLE_PERSISTENT_HEALTH_CHECK_INTERVAL=30
|
|
170
|
+
ORACLE_PERSISTENT_AUTO_RECONNECT=true
|
|
171
|
+
|
|
172
|
+
# MongoDB Database Settings
|
|
173
|
+
MONGODB_HOST=localhost
|
|
174
|
+
MONGODB_PORT=27017
|
|
175
|
+
MONGODB_USER=admin
|
|
176
|
+
MONGODB_PASSWORD=admin
|
|
177
|
+
MONGODB_DATABASE=admin
|
|
178
|
+
MONGODB_BATCH_SIZE=2865
|
|
179
|
+
MONGODB_LIMIT=0
|
|
180
|
+
# TLS settings
|
|
181
|
+
MONGODB_TLS_ENABLED=false
|
|
182
|
+
MONGODB_TLS_CA_CERT_PATH=
|
|
183
|
+
MONGODB_TLS_CERT_KEY_PATH=
|
|
184
|
+
MONGODB_TLS_ALLOW_INVALID_CERTIFICATES=false
|
|
185
|
+
# Connection Retry settings
|
|
186
|
+
MONGODB_CONNECTION_ENABLE_RETRY=true
|
|
187
|
+
MONGODB_CONNECTION_MAX_RETRIES=3
|
|
188
|
+
MONGODB_CONNECTION_INITIAL_RETRY_DELAY=1.0
|
|
189
|
+
MONGODB_CONNECTION_MAX_RETRY_DELAY=30.0
|
|
190
|
+
MONGODB_CONNECTION_DISCONNECT_IDLE_TIMEOUT=300
|
|
191
|
+
# Operation Retry settings
|
|
192
|
+
MONGODB_OPERATION_ENABLE_RETRY=true
|
|
193
|
+
MONGODB_OPERATION_MAX_RETRIES=3
|
|
194
|
+
MONGODB_OPERATION_INITIAL_RETRY_DELAY=0.5
|
|
195
|
+
MONGODB_OPERATION_MAX_RETRY_DELAY=10.0
|
|
196
|
+
MONGODB_OPERATION_JITTER=0.1
|
|
197
|
+
# Persistent connection settings
|
|
198
|
+
MONGODB_PERSISTENT_IDLE_TIMEOUT=300
|
|
199
|
+
MONGODB_PERSISTENT_HEALTH_CHECK_INTERVAL=30
|
|
200
|
+
MONGODB_PERSISTENT_AUTO_RECONNECT=true
|
ddcdatabases/__init__.py
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from .core.operations import DBUtils, DBUtilsAsync
|
|
3
|
+
from .core.persistent import PersistentConnectionConfig, close_all_persistent_connections
|
|
4
|
+
from importlib.metadata import version
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"DBUtils",
|
|
8
|
+
"DBUtilsAsync",
|
|
9
|
+
"PersistentConnectionConfig",
|
|
10
|
+
"close_all_persistent_connections",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
# Conditional imports based on available dependencies
|
|
14
|
+
try:
|
|
15
|
+
from .core.settings import clear_sqlite_settings_cache, get_sqlite_settings
|
|
16
|
+
from .sqlite import (
|
|
17
|
+
Sqlite,
|
|
18
|
+
SqliteConnectionRetryConfig,
|
|
19
|
+
SqliteOperationRetryConfig,
|
|
20
|
+
SqliteSessionConfig,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
__all__ += [
|
|
24
|
+
"Sqlite",
|
|
25
|
+
"SqliteConnectionRetryConfig",
|
|
26
|
+
"SqliteOperationRetryConfig",
|
|
27
|
+
"SqliteSessionConfig",
|
|
28
|
+
"clear_sqlite_settings_cache",
|
|
29
|
+
"get_sqlite_settings",
|
|
30
|
+
]
|
|
31
|
+
except ImportError:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
from .core.persistent import MongoDBPersistent
|
|
36
|
+
from .core.settings import clear_mongodb_settings_cache, get_mongodb_settings
|
|
37
|
+
from .mongodb import (
|
|
38
|
+
MongoDB,
|
|
39
|
+
MongoDBConnectionConfig,
|
|
40
|
+
MongoDBConnectionRetryConfig,
|
|
41
|
+
MongoDBOperationRetryConfig,
|
|
42
|
+
MongoDBQueryConfig,
|
|
43
|
+
MongoDBTLSConfig,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
__all__ += [
|
|
47
|
+
"MongoDB",
|
|
48
|
+
"MongoDBConnectionConfig",
|
|
49
|
+
"MongoDBConnectionRetryConfig",
|
|
50
|
+
"MongoDBOperationRetryConfig",
|
|
51
|
+
"MongoDBPersistent",
|
|
52
|
+
"MongoDBQueryConfig",
|
|
53
|
+
"MongoDBTLSConfig",
|
|
54
|
+
"clear_mongodb_settings_cache",
|
|
55
|
+
"get_mongodb_settings",
|
|
56
|
+
]
|
|
57
|
+
except ImportError:
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
from .core.persistent import MSSQLPersistent
|
|
62
|
+
from .core.settings import clear_mssql_settings_cache, get_mssql_settings
|
|
63
|
+
from .mssql import (
|
|
64
|
+
MSSQL,
|
|
65
|
+
MSSQLConnectionConfig,
|
|
66
|
+
MSSQLConnectionRetryConfig,
|
|
67
|
+
MSSQLOperationRetryConfig,
|
|
68
|
+
MSSQLPoolConfig,
|
|
69
|
+
MSSQLSessionConfig,
|
|
70
|
+
MSSQLSSLConfig,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
__all__ += [
|
|
74
|
+
"MSSQL",
|
|
75
|
+
"MSSQLConnectionConfig",
|
|
76
|
+
"MSSQLConnectionRetryConfig",
|
|
77
|
+
"MSSQLOperationRetryConfig",
|
|
78
|
+
"MSSQLPersistent",
|
|
79
|
+
"MSSQLPoolConfig",
|
|
80
|
+
"MSSQLSessionConfig",
|
|
81
|
+
"MSSQLSSLConfig",
|
|
82
|
+
"clear_mssql_settings_cache",
|
|
83
|
+
"get_mssql_settings",
|
|
84
|
+
]
|
|
85
|
+
except ImportError:
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
from .core.persistent import MySQLPersistent
|
|
90
|
+
from .core.settings import clear_mysql_settings_cache, get_mysql_settings
|
|
91
|
+
from .mysql import (
|
|
92
|
+
MySQL,
|
|
93
|
+
MySQLConnectionConfig,
|
|
94
|
+
MySQLConnectionRetryConfig,
|
|
95
|
+
MySQLOperationRetryConfig,
|
|
96
|
+
MySQLPoolConfig,
|
|
97
|
+
MySQLSessionConfig,
|
|
98
|
+
MySQLSSLConfig,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# MariaDB aliases (MariaDB is fully compatible with MySQL driver)
|
|
102
|
+
MariaDB = MySQL
|
|
103
|
+
MariaDBConnectionConfig = MySQLConnectionConfig
|
|
104
|
+
MariaDBConnectionRetryConfig = MySQLConnectionRetryConfig
|
|
105
|
+
MariaDBOperationRetryConfig = MySQLOperationRetryConfig
|
|
106
|
+
MariaDBPersistent = MySQLPersistent
|
|
107
|
+
MariaDBPoolConfig = MySQLPoolConfig
|
|
108
|
+
MariaDBSessionConfig = MySQLSessionConfig
|
|
109
|
+
MariaDBSSLConfig = MySQLSSLConfig
|
|
110
|
+
clear_mariadb_settings_cache = clear_mysql_settings_cache
|
|
111
|
+
get_mariadb_settings = get_mysql_settings
|
|
112
|
+
|
|
113
|
+
__all__ += [
|
|
114
|
+
"MySQL",
|
|
115
|
+
"MySQLConnectionConfig",
|
|
116
|
+
"MySQLConnectionRetryConfig",
|
|
117
|
+
"MySQLOperationRetryConfig",
|
|
118
|
+
"MySQLPersistent",
|
|
119
|
+
"MySQLPoolConfig",
|
|
120
|
+
"MySQLSessionConfig",
|
|
121
|
+
"MySQLSSLConfig",
|
|
122
|
+
"clear_mysql_settings_cache",
|
|
123
|
+
"get_mysql_settings",
|
|
124
|
+
# MariaDB aliases
|
|
125
|
+
"MariaDB",
|
|
126
|
+
"MariaDBConnectionConfig",
|
|
127
|
+
"MariaDBConnectionRetryConfig",
|
|
128
|
+
"MariaDBOperationRetryConfig",
|
|
129
|
+
"MariaDBPersistent",
|
|
130
|
+
"MariaDBPoolConfig",
|
|
131
|
+
"MariaDBSessionConfig",
|
|
132
|
+
"MariaDBSSLConfig",
|
|
133
|
+
"clear_mariadb_settings_cache",
|
|
134
|
+
"get_mariadb_settings",
|
|
135
|
+
]
|
|
136
|
+
except ImportError:
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
from .core.persistent import OraclePersistent
|
|
141
|
+
from .core.settings import clear_oracle_settings_cache, get_oracle_settings
|
|
142
|
+
from .oracle import (
|
|
143
|
+
Oracle,
|
|
144
|
+
OracleConnectionConfig,
|
|
145
|
+
OracleConnectionRetryConfig,
|
|
146
|
+
OracleOperationRetryConfig,
|
|
147
|
+
OraclePoolConfig,
|
|
148
|
+
OracleSessionConfig,
|
|
149
|
+
OracleSSLConfig,
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
__all__ += [
|
|
153
|
+
"Oracle",
|
|
154
|
+
"OracleConnectionConfig",
|
|
155
|
+
"OracleConnectionRetryConfig",
|
|
156
|
+
"OracleOperationRetryConfig",
|
|
157
|
+
"OraclePersistent",
|
|
158
|
+
"OraclePoolConfig",
|
|
159
|
+
"OracleSessionConfig",
|
|
160
|
+
"OracleSSLConfig",
|
|
161
|
+
"clear_oracle_settings_cache",
|
|
162
|
+
"get_oracle_settings",
|
|
163
|
+
]
|
|
164
|
+
except ImportError:
|
|
165
|
+
pass
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
from .core.persistent import PostgreSQLPersistent
|
|
169
|
+
from .core.settings import clear_postgresql_settings_cache, get_postgresql_settings
|
|
170
|
+
from .postgresql import (
|
|
171
|
+
PostgreSQL,
|
|
172
|
+
PostgreSQLConnectionConfig,
|
|
173
|
+
PostgreSQLConnectionRetryConfig,
|
|
174
|
+
PostgreSQLOperationRetryConfig,
|
|
175
|
+
PostgreSQLPoolConfig,
|
|
176
|
+
PostgreSQLSessionConfig,
|
|
177
|
+
PostgreSQLSSLConfig,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
__all__ += [
|
|
181
|
+
"PostgreSQL",
|
|
182
|
+
"PostgreSQLConnectionConfig",
|
|
183
|
+
"PostgreSQLConnectionRetryConfig",
|
|
184
|
+
"PostgreSQLOperationRetryConfig",
|
|
185
|
+
"PostgreSQLPersistent",
|
|
186
|
+
"PostgreSQLPoolConfig",
|
|
187
|
+
"PostgreSQLSessionConfig",
|
|
188
|
+
"PostgreSQLSSLConfig",
|
|
189
|
+
"clear_postgresql_settings_cache",
|
|
190
|
+
"get_postgresql_settings",
|
|
191
|
+
]
|
|
192
|
+
except ImportError:
|
|
193
|
+
pass
|
|
194
|
+
|
|
195
|
+
__all__ = tuple(__all__)
|
|
196
|
+
__title__ = "ddcdatabases"
|
|
197
|
+
__author__ = "Daniel Costa"
|
|
198
|
+
__email__ = "daniel@ddcsoftwares.com"
|
|
199
|
+
__license__ = "MIT"
|
|
200
|
+
__copyright__ = "Copyright 2024-present DDC Softwares"
|
|
201
|
+
__version__ = version(__title__)
|
|
202
|
+
|
|
203
|
+
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
|
File without changes
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import logging
|
|
3
|
+
import sqlalchemy as sa
|
|
4
|
+
from .configs import BaseOperationRetryConfig, BaseRetryConfig
|
|
5
|
+
from .retry import retry_operation, retry_operation_async
|
|
6
|
+
from collections.abc import AsyncGenerator, Generator
|
|
7
|
+
from contextlib import asynccontextmanager, contextmanager
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from sqlalchemy.engine import URL, Engine, create_engine
|
|
10
|
+
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker, create_async_engine
|
|
11
|
+
from sqlalchemy.orm import Session, sessionmaker
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
_logger = logging.getLogger(__name__)
|
|
15
|
+
_logger.addHandler(logging.NullHandler())
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BaseConnection:
|
|
19
|
+
__slots__ = (
|
|
20
|
+
"connection_url",
|
|
21
|
+
"engine_args",
|
|
22
|
+
"autoflush",
|
|
23
|
+
"expire_on_commit",
|
|
24
|
+
"sync_driver",
|
|
25
|
+
"async_driver",
|
|
26
|
+
"session",
|
|
27
|
+
"is_connected",
|
|
28
|
+
"_temp_engine",
|
|
29
|
+
"connection_retry_config",
|
|
30
|
+
"operation_retry_config",
|
|
31
|
+
"logger",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
connection_url: dict,
|
|
37
|
+
engine_args: dict,
|
|
38
|
+
autoflush: bool,
|
|
39
|
+
expire_on_commit: bool,
|
|
40
|
+
sync_driver: str | None,
|
|
41
|
+
async_driver: str | None,
|
|
42
|
+
connection_retry_config: BaseRetryConfig | None = None,
|
|
43
|
+
operation_retry_config: BaseOperationRetryConfig | None = None,
|
|
44
|
+
logger: Any = None,
|
|
45
|
+
) -> None:
|
|
46
|
+
self.connection_url = connection_url
|
|
47
|
+
self.engine_args = engine_args
|
|
48
|
+
self.autoflush = autoflush
|
|
49
|
+
self.expire_on_commit = expire_on_commit
|
|
50
|
+
self.sync_driver = sync_driver
|
|
51
|
+
self.async_driver = async_driver
|
|
52
|
+
self.session: Session | AsyncSession | None = None
|
|
53
|
+
self.is_connected = False
|
|
54
|
+
self._temp_engine: Engine | AsyncEngine | None = None
|
|
55
|
+
self.connection_retry_config = connection_retry_config or BaseRetryConfig()
|
|
56
|
+
self.operation_retry_config = operation_retry_config or BaseOperationRetryConfig()
|
|
57
|
+
self.logger = logger if logger is not None else _logger
|
|
58
|
+
|
|
59
|
+
def __enter__(self) -> Session:
|
|
60
|
+
def connect() -> Session:
|
|
61
|
+
with self._get_engine() as self._temp_engine:
|
|
62
|
+
session_maker = sessionmaker(
|
|
63
|
+
bind=self._temp_engine,
|
|
64
|
+
class_=Session,
|
|
65
|
+
autoflush=self.autoflush,
|
|
66
|
+
expire_on_commit=self.expire_on_commit,
|
|
67
|
+
)
|
|
68
|
+
with session_maker.begin() as self.session:
|
|
69
|
+
self._test_connection_sync(self.session)
|
|
70
|
+
self.is_connected = True
|
|
71
|
+
return self.session
|
|
72
|
+
|
|
73
|
+
return retry_operation(connect, self.connection_retry_config, "sync_connect", logger=self.logger)
|
|
74
|
+
|
|
75
|
+
def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: Any) -> None:
|
|
76
|
+
if self.session:
|
|
77
|
+
self.session.close()
|
|
78
|
+
if self._temp_engine:
|
|
79
|
+
self._temp_engine.dispose()
|
|
80
|
+
self.is_connected = False
|
|
81
|
+
self.logger.debug("Disconnected")
|
|
82
|
+
|
|
83
|
+
async def __aenter__(self) -> AsyncSession:
|
|
84
|
+
async def connect() -> AsyncSession:
|
|
85
|
+
async with self._get_async_engine() as self._temp_engine:
|
|
86
|
+
session_maker = async_sessionmaker(
|
|
87
|
+
bind=self._temp_engine,
|
|
88
|
+
class_=AsyncSession,
|
|
89
|
+
autoflush=self.autoflush,
|
|
90
|
+
expire_on_commit=self.expire_on_commit,
|
|
91
|
+
)
|
|
92
|
+
async with session_maker.begin() as self.session:
|
|
93
|
+
await self._test_connection_async(self.session)
|
|
94
|
+
self.is_connected = True
|
|
95
|
+
return self.session
|
|
96
|
+
|
|
97
|
+
return await retry_operation_async(connect, self.connection_retry_config, "async_connect", logger=self.logger)
|
|
98
|
+
|
|
99
|
+
async def __aexit__(
|
|
100
|
+
self,
|
|
101
|
+
exc_type: type[BaseException] | None,
|
|
102
|
+
exc_val: BaseException | None,
|
|
103
|
+
exc_tb: Any,
|
|
104
|
+
) -> None:
|
|
105
|
+
if self.session:
|
|
106
|
+
await self.session.close()
|
|
107
|
+
if self._temp_engine:
|
|
108
|
+
await self._temp_engine.dispose()
|
|
109
|
+
self.is_connected = False
|
|
110
|
+
self.logger.debug("Disconnected")
|
|
111
|
+
|
|
112
|
+
@contextmanager
|
|
113
|
+
def _get_engine(self) -> Generator[Engine, None, None]:
|
|
114
|
+
_connection_url = URL.create(drivername=self.sync_driver, **self.connection_url)
|
|
115
|
+
_engine = create_engine(url=_connection_url, **self.engine_args)
|
|
116
|
+
yield _engine
|
|
117
|
+
_engine.dispose()
|
|
118
|
+
|
|
119
|
+
@asynccontextmanager
|
|
120
|
+
async def _get_async_engine(self) -> AsyncGenerator[AsyncEngine, None]:
|
|
121
|
+
_connection_url = URL.create(drivername=self.async_driver, **self.connection_url)
|
|
122
|
+
_engine = create_async_engine(url=_connection_url, **self.engine_args)
|
|
123
|
+
yield _engine
|
|
124
|
+
await _engine.dispose()
|
|
125
|
+
|
|
126
|
+
def _test_connection_sync(self, session: Session) -> None:
|
|
127
|
+
_connection_url_copy = self.connection_url.copy()
|
|
128
|
+
_connection_url_copy.pop("password", None)
|
|
129
|
+
_connection_url = URL.create(
|
|
130
|
+
**_connection_url_copy,
|
|
131
|
+
drivername=self.sync_driver,
|
|
132
|
+
)
|
|
133
|
+
test_connection = ConnectionTester(
|
|
134
|
+
sync_session=session,
|
|
135
|
+
host_url=_connection_url,
|
|
136
|
+
logger=self.logger,
|
|
137
|
+
)
|
|
138
|
+
test_connection.test_connection_sync()
|
|
139
|
+
|
|
140
|
+
async def _test_connection_async(self, session: AsyncSession) -> None:
|
|
141
|
+
_connection_url_copy = self.connection_url.copy()
|
|
142
|
+
_connection_url_copy.pop("password", None)
|
|
143
|
+
_connection_url = URL.create(
|
|
144
|
+
**_connection_url_copy,
|
|
145
|
+
drivername=self.async_driver,
|
|
146
|
+
)
|
|
147
|
+
test_connection = ConnectionTester(
|
|
148
|
+
async_session=session,
|
|
149
|
+
host_url=_connection_url,
|
|
150
|
+
logger=self.logger,
|
|
151
|
+
)
|
|
152
|
+
await test_connection.test_connection_async()
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class ConnectionTester:
|
|
156
|
+
__slots__ = ("sync_session", "async_session", "host_url", "dt", "logger", "failed_msg")
|
|
157
|
+
|
|
158
|
+
def __init__(
|
|
159
|
+
self,
|
|
160
|
+
sync_session: Session | None = None,
|
|
161
|
+
async_session: AsyncSession | None = None,
|
|
162
|
+
host_url: URL | str = "",
|
|
163
|
+
logger: Any = None,
|
|
164
|
+
) -> None:
|
|
165
|
+
self.sync_session = sync_session
|
|
166
|
+
self.async_session = async_session
|
|
167
|
+
self.host_url = host_url
|
|
168
|
+
self.dt = datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
|
|
169
|
+
self.logger = logger if logger is not None else _logger
|
|
170
|
+
self.failed_msg = "Connection to database failed"
|
|
171
|
+
|
|
172
|
+
def test_connection_sync(self) -> bool:
|
|
173
|
+
try:
|
|
174
|
+
query_text = "SELECT 1 FROM dual" if "oracle" in str(self.sync_session.bind.url) else "SELECT 1"
|
|
175
|
+
self.sync_session.execute(sa.text(query_text))
|
|
176
|
+
return True
|
|
177
|
+
except Exception as e:
|
|
178
|
+
self.sync_session.close()
|
|
179
|
+
error_msg = f"[{self.dt}]:[ERROR]:{self.failed_msg} | {self.host_url} | {e!r}"
|
|
180
|
+
self.logger.error(error_msg)
|
|
181
|
+
raise ConnectionRefusedError(f"{self.failed_msg} | {e!r}") from e
|
|
182
|
+
|
|
183
|
+
async def test_connection_async(self) -> bool:
|
|
184
|
+
try:
|
|
185
|
+
query_text = "SELECT 1 FROM dual" if "oracle" in str(self.async_session.bind.url) else "SELECT 1"
|
|
186
|
+
await self.async_session.execute(sa.text(query_text))
|
|
187
|
+
return True
|
|
188
|
+
except Exception as e:
|
|
189
|
+
await self.async_session.close()
|
|
190
|
+
error_msg = f"[{self.dt}]:[ERROR]:{self.failed_msg} | {self.host_url} | {e!r}"
|
|
191
|
+
self.logger.error(error_msg)
|
|
192
|
+
raise ConnectionRefusedError(f"{self.failed_msg} | {e!r}") from e
|