maleo-database 0.0.4__py3-none-any.whl → 0.0.5__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.
- maleo/database/config/__init__.py +188 -15
- maleo/database/config/connection.py +46 -30
- maleo/database/config/pooling.py +171 -83
- maleo/database/dtos.py +6 -0
- maleo/database/managers/__init__.py +427 -0
- maleo/database/managers/client.py +82 -0
- maleo/database/managers/engine.py +64 -0
- maleo/database/managers/session.py +413 -137
- {maleo_database-0.0.4.dist-info → maleo_database-0.0.5.dist-info}/METADATA +23 -8
- maleo_database-0.0.5.dist-info/RECORD +26 -0
- maleo/database/managers/clients/__init__.py +0 -0
- maleo/database/managers/clients/elasticsearch.py +0 -66
- maleo/database/managers/clients/mongodb.py +0 -53
- maleo/database/managers/clients/redis.py +0 -57
- maleo/database/managers/engines/__init__.py +0 -0
- maleo/database/managers/engines/mysql.py +0 -56
- maleo/database/managers/engines/postgresql.py +0 -58
- maleo/database/managers/engines/sqlite.py +0 -55
- maleo/database/managers/engines/sqlserver.py +0 -63
- maleo_database-0.0.4.dist-info/RECORD +0 -32
- {maleo_database-0.0.4.dist-info → maleo_database-0.0.5.dist-info}/WHEEL +0 -0
- {maleo_database-0.0.4.dist-info → maleo_database-0.0.5.dist-info}/licenses/LICENSE +0 -0
- {maleo_database-0.0.4.dist-info → maleo_database-0.0.5.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,14 @@
|
|
1
|
+
from elasticsearch import AsyncElasticsearch, Elasticsearch
|
2
|
+
from motor.motor_asyncio import AsyncIOMotorClient
|
1
3
|
from pydantic import BaseModel, Field
|
2
|
-
from
|
4
|
+
from pymongo import MongoClient
|
5
|
+
from redis.asyncio import Redis as AsyncRedis
|
6
|
+
from redis import Redis as SyncRedis
|
7
|
+
from sqlalchemy.engine import create_engine as create_sync_engine, Engine
|
8
|
+
from sqlalchemy.ext.asyncio import create_async_engine, AsyncEngine
|
9
|
+
from typing import Generic, Literal, TypeVar, Union, overload
|
10
|
+
from maleo.types.base.dict import StringToAnyDict
|
11
|
+
from ..enums import Connection
|
3
12
|
from .additional import AdditionalConfigT, RedisAdditionalConfig
|
4
13
|
from .connection import (
|
5
14
|
ConnectionConfigT,
|
@@ -35,25 +44,61 @@ class BaseDatabaseConfig(
|
|
35
44
|
additional: AdditionalConfigT = Field(..., description="Additional config")
|
36
45
|
|
37
46
|
|
38
|
-
class
|
47
|
+
class MySQLDatabaseConfig(
|
39
48
|
BaseDatabaseConfig[
|
40
|
-
|
41
|
-
|
49
|
+
MySQLConnectionConfig,
|
50
|
+
MySQLPoolingConfig,
|
42
51
|
None,
|
43
52
|
]
|
44
53
|
):
|
45
54
|
additional: None = None
|
46
55
|
|
56
|
+
@property
|
57
|
+
def engine_kwargs(self) -> StringToAnyDict:
|
58
|
+
return {
|
59
|
+
**self.connection.engine_kwargs,
|
60
|
+
**self.pooling.engine_kwargs,
|
61
|
+
}
|
47
62
|
|
48
|
-
|
63
|
+
@overload
|
64
|
+
def create_engine(self, connection: Literal[Connection.ASYNC]) -> AsyncEngine: ...
|
65
|
+
@overload
|
66
|
+
def create_engine(self, connection: Literal[Connection.SYNC]) -> Engine: ...
|
67
|
+
def create_engine(self, connection: Connection) -> Union[AsyncEngine, Engine]:
|
68
|
+
url = self.connection.make_url(connection)
|
69
|
+
if connection is Connection.ASYNC:
|
70
|
+
return create_async_engine(url, **self.engine_kwargs)
|
71
|
+
elif connection is Connection.SYNC:
|
72
|
+
return create_sync_engine(url, **self.engine_kwargs)
|
73
|
+
|
74
|
+
|
75
|
+
class PostgreSQLDatabaseConfig(
|
49
76
|
BaseDatabaseConfig[
|
50
|
-
|
51
|
-
|
77
|
+
PostgreSQLConnectionConfig,
|
78
|
+
PostgreSQLPoolingConfig,
|
52
79
|
None,
|
53
80
|
]
|
54
81
|
):
|
55
82
|
additional: None = None
|
56
83
|
|
84
|
+
@property
|
85
|
+
def engine_kwargs(self) -> StringToAnyDict:
|
86
|
+
return {
|
87
|
+
**self.connection.engine_kwargs,
|
88
|
+
**self.pooling.engine_kwargs,
|
89
|
+
}
|
90
|
+
|
91
|
+
@overload
|
92
|
+
def create_engine(self, connection: Literal[Connection.ASYNC]) -> AsyncEngine: ...
|
93
|
+
@overload
|
94
|
+
def create_engine(self, connection: Literal[Connection.SYNC]) -> Engine: ...
|
95
|
+
def create_engine(self, connection: Connection) -> Union[AsyncEngine, Engine]:
|
96
|
+
url = self.connection.make_url(connection)
|
97
|
+
if connection is Connection.ASYNC:
|
98
|
+
return create_async_engine(url, **self.engine_kwargs)
|
99
|
+
elif connection is Connection.SYNC:
|
100
|
+
return create_sync_engine(url, **self.engine_kwargs)
|
101
|
+
|
57
102
|
|
58
103
|
class SQLiteDatabaseConfig(
|
59
104
|
BaseDatabaseConfig[
|
@@ -64,6 +109,24 @@ class SQLiteDatabaseConfig(
|
|
64
109
|
):
|
65
110
|
additional: None = None
|
66
111
|
|
112
|
+
@property
|
113
|
+
def engine_kwargs(self) -> StringToAnyDict:
|
114
|
+
return {
|
115
|
+
**self.connection.engine_kwargs,
|
116
|
+
**self.pooling.engine_kwargs,
|
117
|
+
}
|
118
|
+
|
119
|
+
@overload
|
120
|
+
def create_engine(self, connection: Literal[Connection.ASYNC]) -> AsyncEngine: ...
|
121
|
+
@overload
|
122
|
+
def create_engine(self, connection: Literal[Connection.SYNC]) -> Engine: ...
|
123
|
+
def create_engine(self, connection: Connection) -> Union[AsyncEngine, Engine]:
|
124
|
+
url = self.connection.make_url(connection)
|
125
|
+
if connection is Connection.ASYNC:
|
126
|
+
return create_async_engine(url, **self.engine_kwargs)
|
127
|
+
elif connection is Connection.SYNC:
|
128
|
+
return create_sync_engine(url, **self.engine_kwargs)
|
129
|
+
|
67
130
|
|
68
131
|
class SQLServerDatabaseConfig(
|
69
132
|
BaseDatabaseConfig[
|
@@ -74,6 +137,72 @@ class SQLServerDatabaseConfig(
|
|
74
137
|
):
|
75
138
|
additional: None = None
|
76
139
|
|
140
|
+
@property
|
141
|
+
def engine_kwargs(self) -> StringToAnyDict:
|
142
|
+
return {
|
143
|
+
**self.connection.engine_kwargs,
|
144
|
+
**self.pooling.engine_kwargs,
|
145
|
+
}
|
146
|
+
|
147
|
+
@overload
|
148
|
+
def create_engine(self, connection: Literal[Connection.ASYNC]) -> AsyncEngine: ...
|
149
|
+
@overload
|
150
|
+
def create_engine(self, connection: Literal[Connection.SYNC]) -> Engine: ...
|
151
|
+
def create_engine(self, connection: Connection) -> Union[AsyncEngine, Engine]:
|
152
|
+
url = self.connection.make_url(connection)
|
153
|
+
if connection is Connection.ASYNC:
|
154
|
+
return create_async_engine(url, **self.engine_kwargs)
|
155
|
+
elif connection is Connection.SYNC:
|
156
|
+
return create_sync_engine(url, **self.engine_kwargs)
|
157
|
+
|
158
|
+
|
159
|
+
SQLConfigT = TypeVar(
|
160
|
+
"SQLConfigT",
|
161
|
+
PostgreSQLDatabaseConfig,
|
162
|
+
MySQLDatabaseConfig,
|
163
|
+
SQLiteDatabaseConfig,
|
164
|
+
SQLServerDatabaseConfig,
|
165
|
+
)
|
166
|
+
|
167
|
+
|
168
|
+
class ElasticsearchDatabaseConfig(
|
169
|
+
BaseDatabaseConfig[
|
170
|
+
ElasticsearchConnectionConfig,
|
171
|
+
ElasticsearchPoolingConfig,
|
172
|
+
None,
|
173
|
+
]
|
174
|
+
):
|
175
|
+
additional: None = None
|
176
|
+
|
177
|
+
@property
|
178
|
+
def client_kwargs(self) -> StringToAnyDict:
|
179
|
+
client_kwargs = {}
|
180
|
+
|
181
|
+
if self.connection.username and self.connection.password:
|
182
|
+
client_kwargs["http_auth"] = (
|
183
|
+
self.connection.username,
|
184
|
+
self.connection.password,
|
185
|
+
)
|
186
|
+
|
187
|
+
client_kwargs.update(self.pooling.client_kwargs)
|
188
|
+
|
189
|
+
return client_kwargs
|
190
|
+
|
191
|
+
@overload
|
192
|
+
def create_client(
|
193
|
+
self, connection: Literal[Connection.ASYNC]
|
194
|
+
) -> AsyncElasticsearch: ...
|
195
|
+
@overload
|
196
|
+
def create_client(self, connection: Literal[Connection.SYNC]) -> Elasticsearch: ...
|
197
|
+
def create_client(
|
198
|
+
self, connection: Connection
|
199
|
+
) -> Union[AsyncElasticsearch, Elasticsearch]:
|
200
|
+
hosts = [{"host": self.connection.host, "port": self.connection.port}]
|
201
|
+
if connection is Connection.ASYNC:
|
202
|
+
return AsyncElasticsearch(hosts, **self.client_kwargs)
|
203
|
+
else:
|
204
|
+
return Elasticsearch(hosts, **self.client_kwargs)
|
205
|
+
|
77
206
|
|
78
207
|
class MongoDBDatabaseConfig(
|
79
208
|
BaseDatabaseConfig[
|
@@ -84,6 +213,25 @@ class MongoDBDatabaseConfig(
|
|
84
213
|
):
|
85
214
|
additional: None = None
|
86
215
|
|
216
|
+
@property
|
217
|
+
def client_kwargs(self) -> StringToAnyDict:
|
218
|
+
return self.pooling.client_kwargs
|
219
|
+
|
220
|
+
@overload
|
221
|
+
def create_client(
|
222
|
+
self, connection: Literal[Connection.ASYNC]
|
223
|
+
) -> AsyncIOMotorClient: ...
|
224
|
+
@overload
|
225
|
+
def create_client(self, connection: Literal[Connection.SYNC]) -> MongoClient: ...
|
226
|
+
def create_client(
|
227
|
+
self, connection: Connection
|
228
|
+
) -> Union[AsyncIOMotorClient, MongoClient]:
|
229
|
+
url = self.connection.make_url(connection)
|
230
|
+
if connection is Connection.ASYNC:
|
231
|
+
return AsyncIOMotorClient(url, **self.client_kwargs)
|
232
|
+
else:
|
233
|
+
return MongoClient(url, **self.client_kwargs)
|
234
|
+
|
87
235
|
|
88
236
|
class RedisDatabaseConfig(
|
89
237
|
BaseDatabaseConfig[
|
@@ -94,12 +242,37 @@ class RedisDatabaseConfig(
|
|
94
242
|
):
|
95
243
|
additional: RedisAdditionalConfig = Field(..., description="Additional config")
|
96
244
|
|
245
|
+
@property
|
246
|
+
def client_kwargs(self) -> StringToAnyDict:
|
247
|
+
return self.pooling.client_kwargs
|
97
248
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
249
|
+
@overload
|
250
|
+
def create_client(self, connection: Literal[Connection.ASYNC]) -> AsyncRedis: ...
|
251
|
+
@overload
|
252
|
+
def create_client(self, connection: Literal[Connection.SYNC]) -> SyncRedis: ...
|
253
|
+
def create_client(self, connection: Connection) -> Union[AsyncRedis, SyncRedis]:
|
254
|
+
url = self.connection.make_url(connection)
|
255
|
+
if connection is Connection.ASYNC:
|
256
|
+
return AsyncRedis.from_url(url, **self.client_kwargs)
|
257
|
+
else:
|
258
|
+
return SyncRedis.from_url(url, **self.client_kwargs)
|
259
|
+
|
260
|
+
|
261
|
+
NoSQLConfigT = TypeVar(
|
262
|
+
"NoSQLConfigT",
|
263
|
+
ElasticsearchDatabaseConfig,
|
264
|
+
MongoDBDatabaseConfig,
|
265
|
+
RedisDatabaseConfig,
|
266
|
+
)
|
267
|
+
|
268
|
+
|
269
|
+
ConfigT = TypeVar(
|
270
|
+
"ConfigT",
|
271
|
+
PostgreSQLDatabaseConfig,
|
272
|
+
MySQLDatabaseConfig,
|
273
|
+
SQLiteDatabaseConfig,
|
274
|
+
SQLServerDatabaseConfig,
|
275
|
+
MongoDBDatabaseConfig,
|
276
|
+
RedisDatabaseConfig,
|
277
|
+
ElasticsearchDatabaseConfig,
|
278
|
+
)
|
@@ -241,6 +241,41 @@ class BaseConnectionConfig(
|
|
241
241
|
ConnectionConfigT = TypeVar("ConnectionConfigT", bound=BaseConnectionConfig)
|
242
242
|
|
243
243
|
|
244
|
+
class MySQLConnectionConfig(
|
245
|
+
BaseConnectionConfig[Literal[Driver.MYSQL], str, str, str, int, str]
|
246
|
+
):
|
247
|
+
driver: Literal[Driver.MYSQL] = Driver.MYSQL
|
248
|
+
port: int = Field(3306, description="MySQL port")
|
249
|
+
username: str = Field("root", description="MySQL username")
|
250
|
+
|
251
|
+
# MySQL-specific options
|
252
|
+
echo: bool = Field(False, description="Enable SQL statement logging")
|
253
|
+
charset: MySQLCharset = Field(MySQLCharset.UTF8MB4, description="Character set")
|
254
|
+
|
255
|
+
def _make_mysql_url(self, connection: Connection = Connection.ASYNC) -> str:
|
256
|
+
"""MySQL database URL format with proper async/sync drivers."""
|
257
|
+
# Choose appropriate driver based on connection type
|
258
|
+
if connection is Connection.ASYNC:
|
259
|
+
driver_name = "mysql+aiomysql"
|
260
|
+
elif connection is Connection.SYNC:
|
261
|
+
driver_name = "mysql+pymysql" # or mysqlclient
|
262
|
+
else:
|
263
|
+
driver_name = "mysql" # Default
|
264
|
+
|
265
|
+
encoded_user = self._safe_encode_credential(self.username)
|
266
|
+
encoded_pass = self._safe_encode_credential(self.password)
|
267
|
+
|
268
|
+
base_url = f"{driver_name}://{encoded_user}:{encoded_pass}@{self.host}:{self.port}/{self.database}"
|
269
|
+
|
270
|
+
# Add MySQL-specific options
|
271
|
+
mysql_options = {"charset": self.charset}
|
272
|
+
return base_url + self._make_options_string(mysql_options)
|
273
|
+
|
274
|
+
@property
|
275
|
+
def engine_kwargs(self) -> StringToAnyDict:
|
276
|
+
return self.model_dump(include={"echo"}, exclude_none=True)
|
277
|
+
|
278
|
+
|
244
279
|
class PostgreSQLConnectionConfig(
|
245
280
|
BaseConnectionConfig[Literal[Driver.POSTGRESQL], str, str, str, int, str]
|
246
281
|
):
|
@@ -279,36 +314,9 @@ class PostgreSQLConnectionConfig(
|
|
279
314
|
|
280
315
|
return base_url + self._make_options_string(pg_options)
|
281
316
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
):
|
286
|
-
driver: Literal[Driver.MYSQL] = Driver.MYSQL
|
287
|
-
port: int = Field(3306, description="MySQL port")
|
288
|
-
username: str = Field("root", description="MySQL username")
|
289
|
-
|
290
|
-
# MySQL-specific options
|
291
|
-
echo: bool = Field(False, description="Enable SQL statement logging")
|
292
|
-
charset: MySQLCharset = Field(MySQLCharset.UTF8MB4, description="Character set")
|
293
|
-
|
294
|
-
def _make_mysql_url(self, connection: Connection = Connection.ASYNC) -> str:
|
295
|
-
"""MySQL database URL format with proper async/sync drivers."""
|
296
|
-
# Choose appropriate driver based on connection type
|
297
|
-
if connection is Connection.ASYNC:
|
298
|
-
driver_name = "mysql+aiomysql"
|
299
|
-
elif connection is Connection.SYNC:
|
300
|
-
driver_name = "mysql+pymysql" # or mysqlclient
|
301
|
-
else:
|
302
|
-
driver_name = "mysql" # Default
|
303
|
-
|
304
|
-
encoded_user = self._safe_encode_credential(self.username)
|
305
|
-
encoded_pass = self._safe_encode_credential(self.password)
|
306
|
-
|
307
|
-
base_url = f"{driver_name}://{encoded_user}:{encoded_pass}@{self.host}:{self.port}/{self.database}"
|
308
|
-
|
309
|
-
# Add MySQL-specific options
|
310
|
-
mysql_options = {"charset": self.charset}
|
311
|
-
return base_url + self._make_options_string(mysql_options)
|
317
|
+
@property
|
318
|
+
def engine_kwargs(self) -> StringToAnyDict:
|
319
|
+
return self.model_dump(include={"echo"}, exclude_none=True)
|
312
320
|
|
313
321
|
|
314
322
|
class SQLiteConnectionConfig(
|
@@ -339,6 +347,10 @@ class SQLiteConnectionConfig(
|
|
339
347
|
base_url = f"{driver_name}:///{self.database}"
|
340
348
|
return base_url + self._make_options_string()
|
341
349
|
|
350
|
+
@property
|
351
|
+
def engine_kwargs(self) -> StringToAnyDict:
|
352
|
+
return self.model_dump(include={"echo"}, exclude_none=True)
|
353
|
+
|
342
354
|
|
343
355
|
class SQLServerConnectionConfig(
|
344
356
|
BaseConnectionConfig[Literal[Driver.MSSQL], str, str, str, int, str]
|
@@ -392,6 +404,10 @@ class SQLServerConnectionConfig(
|
|
392
404
|
}
|
393
405
|
return base_url + self._make_options_string(mssql_options)
|
394
406
|
|
407
|
+
@property
|
408
|
+
def engine_kwargs(self) -> StringToAnyDict:
|
409
|
+
return self.model_dump(include={"echo"}, exclude_none=True)
|
410
|
+
|
395
411
|
|
396
412
|
class MongoDBConnectionConfig(
|
397
413
|
BaseConnectionConfig[
|