Skip to content

Commit 3a3b198

Browse files
authored
v4.0.0 (#41)
* v4.0.0 * v4.0.0 * v4.0.0 * v4.0.0 * v4.0.0
1 parent d1a38e8 commit 3a3b198

70 files changed

Lines changed: 1040 additions & 1380 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/PULL_REQUEST_TEMPLATE

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,10 @@
1212
- [ ] Documentation
1313
- [ ] CI/CD or build configuration
1414
- [ ] Dependencies update
15+
- [ ] Other
1516

1617
## Testing
17-
- [ ] Unit tests added/updated
18-
- [ ] Integration tests added/updated
19-
- [ ] All existing tests pass
2018
- [ ] Manual testing performed
2119

22-
## Checklist
23-
- [ ] Code follows the project's style and conventions
24-
- [ ] Documentation updated (if applicable)
25-
- [ ] No new warnings or linter errors introduced
26-
- [ ] I have considered how this change may affect other services
27-
2820
## Reviewer
2921
- [ ] I understand that by approving this PR, I share responsibility for these changes

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2024-present ddc
3+
Copyright (C) 2024 DDC Softwares
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,31 @@
11
<h1 align="center">
2-
<img src="https://raw.githubusercontent.com/ddc/ddcDatabases/main/assets/database-icon.svg" alt="ddcDatabases" width="150">
2+
<img src="https://raw.githubusercontent.com/ddc/ddcDatabases/main/assets/database-icon.svg" alt="ddcdatabases" width="150">
33
<br>
4-
ddcDatabases
4+
ddcdatabases
55
</h1>
66

77
<p align="center">
8-
<a href="https://www.paypal.com/ncp/payment/6G9Z78QHUD4RJ"><img src="https://img.shields.io/badge/Donate-PayPal-brightgreen.svg?style=plastic" alt="Donate"/></a>
98
<a href="https://github.com/sponsors/ddc"><img src="https://img.shields.io/static/v1?style=plastic&label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=ff69b4" alt="Sponsor"/></a>
109
<br>
11-
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg?style=plastic" alt="License: MIT"/></a>
12-
<a href="https://pepy.tech/projects/ddcDatabases"><img src="https://static.pepy.tech/badge/ddcDatabases?style=plastic" alt="PyPI Downloads"/></a>
10+
<a href="https://ko-fi.com/ddcsta"><img src="https://img.shields.io/badge/Ko--fi-ddcsta-FF5E5B?style=plastic&logo=kofi&logoColor=white&color=brightgreen" alt="Ko-fi"/></a>
11+
<a href="https://www.paypal.com/ncp/payment/6G9Z78QHUD4RJ"><img src="https://img.shields.io/badge/Donate-PayPal-brightgreen.svg?style=plastic&logo=paypal&logoColor=white" alt="Donate"/></a>
12+
<br>
1313
<a href="https://pypi.python.org/pypi/ddcDatabases"><img src="https://img.shields.io/pypi/v/ddcDatabases.svg?style=plastic&logo=python&cacheSeconds=3600" alt="PyPi"/></a>
14+
<a href="https://pepy.tech/projects/ddcDatabases"><img src="https://img.shields.io/pepy/dt/ddcDatabases?style=plastic&logo=pypi&logoColor=3776AB" alt="PyPI Downloads"/></a>
15+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg?style=plastic&logo=creativecommons&logoColor=white" alt="License: MIT"/></a>
1416
<br>
1517
<a href="https://www.python.org/downloads"><img src="https://img.shields.io/pypi/pyversions/ddcDatabases.svg?style=plastic&logo=python&cacheSeconds=3600" alt="Python"/></a>
16-
<a href="https://github.com/astral-sh/uv"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json?style=plastic" alt="uv"/></a>
17-
<a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json?style=plastic" alt="Ruff"/></a>
18+
<a href="https://github.com/astral-sh/uv"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json&style=plastic" alt="uv"/></a>
19+
<a href="https://github.com/astral-sh/ruff"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json&style=plastic" alt="Ruff"/></a>
1820
<br>
19-
<a href="https://github.com/ddc/ddcDatabases/issues"><img src="https://img.shields.io/github/issues/ddc/ddcDatabases?style=plastic" alt="issues"/></a>
20-
<a href="https://codecov.io/gh/ddc/ddcDatabases"><img src="https://codecov.io/gh/ddc/ddcDatabases/graph/badge.svg?token=XWB53034GI&style=plastic" alt="codecov"/></a>
21-
<a href="https://sonarcloud.io/dashboard?id=ddc_ddcDatabases"><img src="https://sonarcloud.io/api/project_badges/measure?project=ddc_ddcDatabases&metric=alert_status&style=plastic" alt="Quality Gate Status"/></a>
22-
<a href="https://github.com/ddc/ddcDatabases/actions/workflows/workflow.yml"><img src="https://github.com/ddc/ddcDatabases/actions/workflows/workflow.yml/badge.svg?style=plastic" alt="CI/CD Pipeline"/></a>
23-
<a href="https://actions-badge.atrox.dev/ddc/ddcDatabases/goto?ref=main"><img src="https://img.shields.io/endpoint.svg?url=https%3A//actions-badge.atrox.dev/ddc/ddcDatabases/badge?ref=main&label=build&logo=none&style=plastic" alt="Build Status"/></a>
21+
<a href="https://github.com/ddc/ddcDatabases/issues"><img src="https://img.shields.io/github/issues/ddc/ddcDatabases?style=plastic&logo=github&logoColor=white" alt="issues"/></a>
22+
<a href="https://codecov.io/gh/ddc/ddcDatabases"><img src="https://img.shields.io/codecov/c/github/ddc/ddcDatabases?token=XWB53034GI&style=plastic&logo=codecov" alt="codecov"/></a>
23+
<a href="https://sonarcloud.io/dashboard?id=ddc_ddcDatabases"><img src="https://img.shields.io/sonar/quality_gate/ddc_ddcDatabases?server=https%3A%2F%2Fsonarcloud.io&style=plastic&logo=sonarqubecloud&logoColor=white" alt="Quality Gate Status"/></a>
24+
<a href="https://github.com/ddc/ddcDatabases/actions/workflows/workflow.yml"><img src="https://img.shields.io/github/actions/workflow/status/ddc/ddcDatabases/workflow.yml?style=plastic&logo=github&logoColor=white&label=CI%2FCD%20Pipeline" alt="CI/CD Pipeline"/></a>
25+
<a href="https://actions-badge.atrox.dev/ddc/ddcDatabases/goto?ref=main"><img src="https://img.shields.io/endpoint.svg?url=https%3A//actions-badge.atrox.dev/ddc/ddcDatabases/badge?ref=main&label=build&logo=github&style=plastic" alt="Build Status"/></a>
2426
</p>
2527

26-
<p align="center">A Python library for database connections and ORM queries with support for multiple database engines including SQLite, PostgreSQL, MySQL, MariaDB, MSSQL, Oracle, and MongoDB</p>
28+
<p align="center">A Python library for database connections and ORM queries with support for multiple database engines. <br> Includes SQLite, PostgreSQL, MySQL/MariaDB, MSSQL, Oracle, and MongoDB</p>
2729

2830

2931
# Table of Contents
@@ -81,7 +83,7 @@
8183
| MySQL | `True` | Autocommit ON is MySQL's default |
8284
| Oracle | `False` | Requires explicit COMMIT |
8385

84-
**Note:** All constructor parameters are optional and fall back to [.env](./ddcDatabases/.env.example) file variables.
86+
**Note:** All constructor parameters are optional and fall back to [.env](./ddcdatabases/.env.example) file variables.
8587

8688

8789
## Configuration Classes
@@ -121,7 +123,7 @@ Retry with exponential backoff is enabled by default at two levels:
121123

122124
**1. Connection Level** - Retries when establishing database connections:
123125
```python
124-
from ddcDatabases import PostgreSQL, PostgreSQLConnectionRetryConfig
126+
from ddcdatabases import PostgreSQL, PostgreSQLConnectionRetryConfig
125127

126128
with PostgreSQL(
127129
connection_retry_config=PostgreSQLConnectionRetryConfig(
@@ -137,7 +139,7 @@ with PostgreSQL(
137139

138140
**2. Operation Level** - Retries individual database operations (fetchall, insert, etc.):
139141
```python
140-
from ddcDatabases import DBUtils, PostgreSQL, PostgreSQLOperationRetryConfig
142+
from ddcdatabases import DBUtils, PostgreSQL, PostgreSQLOperationRetryConfig
141143

142144
with PostgreSQL(
143145
operation_retry_config=PostgreSQLOperationRetryConfig(
@@ -170,7 +172,7 @@ with PostgreSQL(
170172
For long-running applications, use persistent connections with automatic reconnection and idle timeout:
171173

172174
```python
173-
from ddcDatabases import (
175+
from ddcdatabases import (
174176
PostgreSQLPersistent,
175177
MySQLPersistent,
176178
MongoDBPersistent,
@@ -230,7 +232,7 @@ The `execute_with_retry` method provides automatic session management with retry
230232

231233
**Synchronous:**
232234
```python
233-
from ddcDatabases import PostgreSQLPersistent
235+
from ddcdatabases import PostgreSQLPersistent
234236

235237
db = PostgreSQLPersistent(logger=logger)
236238
result = db.execute_with_retry(
@@ -240,7 +242,7 @@ result = db.execute_with_retry(
240242

241243
**Asynchronous:**
242244
```python
243-
from ddcDatabases import PostgreSQLPersistent
245+
from ddcdatabases import PostgreSQLPersistent
244246

245247
db = PostgreSQLPersistent(async_mode=True, logger=logger)
246248
result = await db.execute_with_retry(
@@ -267,7 +269,7 @@ The method automatically:
267269

268270
## Basic Installation (SQLite only)
269271
```shell
270-
pip install ddcDatabases
272+
pip install ddcdatabases
271273
```
272274

273275
**Note:** The basic installation includes only SQlite. Database-specific drivers are optional extras that you can install as needed.
@@ -278,29 +280,29 @@ Install only the database drivers you need:
278280

279281
```shell
280282
# All database drivers
281-
pip install "ddcDatabases[all]"
283+
pip install "ddcdatabases[all]"
282284

283285
# SQL Server / MSSQL
284-
pip install "ddcDatabases[mssql]"
286+
pip install "ddcdatabases[mssql]"
285287

286288
# MySQL/MariaDB
287-
pip install "ddcDatabases[mysql]"
289+
pip install "ddcdatabases[mysql]"
288290
# or
289-
pip install "ddcDatabases[mariadb]"
291+
pip install "ddcdatabases[mariadb]"
290292

291293
# PostgreSQL
292-
pip install "ddcDatabases[postgres]"
294+
pip install "ddcdatabases[postgres]"
293295
# or
294-
pip install "ddcDatabases[pgsql]"
296+
pip install "ddcdatabases[pgsql]"
295297

296298
# Oracle Database
297-
pip install "ddcDatabases[oracle]"
299+
pip install "ddcdatabases[oracle]"
298300

299301
# MongoDB
300-
pip install "ddcDatabases[mongodb]"
302+
pip install "ddcdatabases[mongodb]"
301303

302304
# Multiple databases (example)
303-
pip install "ddcDatabases[mysql,postgres,mongodb]"
305+
pip install "ddcdatabases[mysql,postgres,mongodb]"
304306
```
305307

306308
**Available Database Extras:**
@@ -329,7 +331,7 @@ pip install "ddcDatabases[mysql,postgres,mongodb]"
329331

330332
```python
331333
import sqlalchemy as sa
332-
from ddcDatabases import DBUtils, Sqlite
334+
from ddcdatabases import DBUtils, Sqlite
333335
from your_models import Model # Your SQLAlchemy model
334336

335337
with Sqlite(filepath="data.db") as session:
@@ -347,7 +349,7 @@ with Sqlite(filepath="data.db") as session:
347349

348350
```python
349351
import sqlalchemy as sa
350-
from ddcDatabases import DBUtils, MSSQL, MSSQLPoolConfig, MSSQLSessionConfig, MSSQLSSLConfig
352+
from ddcdatabases import DBUtils, MSSQL, MSSQLPoolConfig, MSSQLSessionConfig, MSSQLSSLConfig
351353

352354
with MSSQL(
353355
host="127.0.0.1",
@@ -385,7 +387,7 @@ with MSSQL(
385387
```python
386388
import asyncio
387389
import sqlalchemy as sa
388-
from ddcDatabases import DBUtilsAsync, MSSQL
390+
from ddcdatabases import DBUtilsAsync, MSSQL
389391
from your_models import Model
390392

391393
async def main():
@@ -405,7 +407,7 @@ asyncio.run(main())
405407

406408
```python
407409
import sqlalchemy as sa
408-
from ddcDatabases import DBUtils, PostgreSQL, PostgreSQLPoolConfig, PostgreSQLSessionConfig, PostgreSQLSSLConfig
410+
from ddcdatabases import DBUtils, PostgreSQL, PostgreSQLPoolConfig, PostgreSQLSessionConfig, PostgreSQLSSLConfig
409411

410412
with PostgreSQL(
411413
host="127.0.0.1",
@@ -445,7 +447,7 @@ with PostgreSQL(
445447
```python
446448
import asyncio
447449
import sqlalchemy as sa
448-
from ddcDatabases import DBUtilsAsync, PostgreSQL
450+
from ddcdatabases import DBUtilsAsync, PostgreSQL
449451
from your_models import Model
450452

451453
async def main():
@@ -465,15 +467,15 @@ The MySQL class is fully compatible with both MySQL and MariaDB databases. For c
465467

466468
```python
467469
# Both imports are equivalent
468-
from ddcDatabases import MySQL, MySQLPoolConfig, MySQLSessionConfig
469-
from ddcDatabases import MariaDB, MariaDBPoolConfig, MariaDBSessionConfig # Aliases
470+
from ddcdatabases import MySQL, MySQLPoolConfig, MySQLSessionConfig
471+
from ddcdatabases import MariaDB, MariaDBPoolConfig, MariaDBSessionConfig # Aliases
470472
```
471473

472474
**Synchronous Example:**
473475

474476
```python
475477
import sqlalchemy as sa
476-
from ddcDatabases import DBUtils, MySQL, MySQLPoolConfig, MySQLSessionConfig, MySQLSSLConfig
478+
from ddcdatabases import DBUtils, MySQL, MySQLPoolConfig, MySQLSessionConfig, MySQLSSLConfig
477479

478480
with MySQL(
479481
host="127.0.0.1",
@@ -512,7 +514,7 @@ with MySQL(
512514
```python
513515
import asyncio
514516
import sqlalchemy as sa
515-
from ddcDatabases import DBUtilsAsync, MySQL
517+
from ddcdatabases import DBUtilsAsync, MySQL
516518

517519
async def main() -> None:
518520
async with MySQL(host="127.0.0.1", database="dev") as session:
@@ -531,7 +533,7 @@ asyncio.run(main())
531533

532534
```python
533535
import sqlalchemy as sa
534-
from ddcDatabases import DBUtils, Oracle, OraclePoolConfig, OracleSessionConfig, OracleSSLConfig
536+
from ddcdatabases import DBUtils, Oracle, OraclePoolConfig, OracleSessionConfig, OracleSSLConfig
535537

536538
with Oracle(
537539
host="127.0.0.1",
@@ -572,7 +574,7 @@ with Oracle(
572574
**Example:**
573575

574576
```python
575-
from ddcDatabases import MongoDB, MongoDBQueryConfig, MongoDBTLSConfig
577+
from ddcdatabases import MongoDB, MongoDBQueryConfig, MongoDBTLSConfig
576578
from bson.objectid import ObjectId
577579

578580
with MongoDB(
@@ -609,7 +611,7 @@ Access the underlying SQLAlchemy engine for advanced operations:
609611
**Synchronous Engine:**
610612

611613
```python
612-
from ddcDatabases import PostgreSQL
614+
from ddcdatabases import PostgreSQL
613615

614616
with PostgreSQL() as session:
615617
engine = session.bind
@@ -620,7 +622,7 @@ with PostgreSQL() as session:
620622

621623
```python
622624
import asyncio
623-
from ddcDatabases import PostgreSQL
625+
from ddcdatabases import PostgreSQL
624626

625627
async def main():
626628
async with PostgreSQL() as session:
@@ -638,7 +640,7 @@ The `DBUtils` and `DBUtilsAsync` classes provide convenient methods for common d
638640
## Available Methods
639641

640642
```python
641-
from ddcDatabases import DBUtils, DBUtilsAsync, PostgreSQL
643+
from ddcdatabases import DBUtils, DBUtilsAsync, PostgreSQL
642644

643645
# Synchronous utilities
644646
with PostgreSQL() as session:
@@ -668,7 +670,7 @@ All database classes accept an optional `logger` parameter. By default, logs are
668670

669671
```python
670672
import logging
671-
from ddcDatabases import PostgreSQL, DBUtils
673+
from ddcdatabases import PostgreSQL, DBUtils
672674

673675
log = logging.getLogger("myapp")
674676
log.setLevel(logging.DEBUG)
@@ -683,8 +685,8 @@ with PostgreSQL(host="localhost", database="mydb", logger=log) as session:
683685

684686
```python
685687
import logging
686-
logging.getLogger("ddcDatabases").setLevel(logging.DEBUG)
687-
logging.getLogger("ddcDatabases").addHandler(logging.StreamHandler())
688+
logging.getLogger("ddcdatabases").setLevel(logging.DEBUG)
689+
logging.getLogger("ddcdatabases").addHandler(logging.StreamHandler())
688690
```
689691

690692

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# ddcDatabases Environment Variables Example
1+
# ddcdatabases Environment Variables Example
22
# Copy this file to .env and adjust values as needed
33

44
# SQLite Database Settings
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@
193193
pass
194194

195195
__all__ = tuple(__all__)
196-
__title__ = "ddcDatabases"
196+
__title__ = "ddcdatabases"
197197
__author__ = "Daniel Costa"
198198
__email__ = "daniel@ddcsoftwares.com"
199199
__license__ = "MIT"
Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
from __future__ import annotations
2-
32
import logging
43
import sqlalchemy as sa
54
from .configs import BaseOperationRetryConfig, BaseRetryConfig
65
from .retry import retry_operation, retry_operation_async
7-
from abc import ABC, abstractmethod
8-
from contextlib import AbstractAsyncContextManager, AbstractContextManager
6+
from collections.abc import AsyncGenerator, Generator
7+
from contextlib import asynccontextmanager, contextmanager
98
from datetime import datetime
10-
from sqlalchemy.engine import URL, Engine
11-
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
9+
from sqlalchemy.engine import URL, Engine, create_engine
10+
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker, create_async_engine
1211
from sqlalchemy.orm import Session, sessionmaker
1312
from typing import Any
1413

1514
_logger = logging.getLogger(__name__)
1615
_logger.addHandler(logging.NullHandler())
1716

1817

19-
class BaseConnection(ABC):
18+
class BaseConnection:
2019
__slots__ = (
2120
"connection_url",
2221
"engine_args",
@@ -110,13 +109,19 @@ async def __aexit__(
110109
self.is_connected = False
111110
self.logger.debug("Disconnected")
112111

113-
@abstractmethod
114-
def _get_engine(self) -> AbstractContextManager[Engine]:
115-
pass
116-
117-
@abstractmethod
118-
def _get_async_engine(self) -> AbstractAsyncContextManager[AsyncEngine]:
119-
pass
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()
120125

121126
def _test_connection_sync(self, session: Session) -> None:
122127
_connection_url_copy = self.connection_url.copy()

0 commit comments

Comments
 (0)