Skip to content

Commit 8c9f001

Browse files
authored
Replace databases with sqlalchemy async (#1515)
* Replace databases library with SQLAlchemy async API Migrate the project from the databases library to using SQLAlchemy's native async API directly. - ormar/connection.py: DatabaseConnection class that wraps AsyncEngine - ormar/query_executor.py: QueryExecutor class for database operations - ormar/transaction.py: Transaction management with savepoint support - Updated OrmarConfig, QuerySet, Model, and related files to use new async patterns - Simplified SQLite pragma handling - Updated all dialect access patterns - Updated test files to use DatabaseConnection and async drivers - Changed DDL operations to use async engine with run_sync() * Fix connection management and transaction handling Fixes critical connection pool exhaustion and transaction handling issues. Key changes: - Removed auto-commit from QueryExecutor - Use engine.begin() for auto-commit connections - Added connection pool limits (pool_size=5, max_overflow=10) - Fixed transaction connection reuse * fix all tests to pass * fix all tests to pass in all backends * update gitignore * add no cover to sqlite test in lifespan for other engines related part * quick and ugly docs src fix to pass test docs workflow * remove unused substitue_backend_pool_for_sqlite and duplicate code in model.py * simplify getting the query executor to avoid code duplication * simplify prefetch related query * add back force rollback to signals that was not working with databases, remove unused cleanup, double check force rollback on db without transaction is working too * add more tests for transactions, ensure sqlite transaction rollback with nested transactions * fix depth check and change to value error to avoid swallowing exceptions in transactions tests * remove engine from docs sources as its optional and we handle db creation and drop separately * fix example too * updates the lines references after the docs changes and fixes * updates the documentation to reflect the new DatabaseConnection dependency and migration to async SQLAlchemy. Add migration example and update dependencies for async support. * add relases and bump version to 0.22.0 * bump version to 0.22.0 * bump poetry version in workflows * fix benchmarks not connected error * bump pytest-asyncio version to 1.2.0 and update benchmarks to not use event loop fixture * bump pytest-cov * restore benchmark fixture decorator * revert pytest-asyncio to check pipeline * check 1.2 version of pytest-asyncio * Revert "check 1.2 version of pytest-asyncio" This reverts commit e964f44. * Reapply "check 1.2 version of pytest-asyncio" This reverts commit 437b956. * check if new fixture is messing up the coverage * Revert "check if new fixture is messing up the coverage" This reverts commit 0353e49. * Revert "Reapply "check 1.2 version of pytest-asyncio"" This reverts commit e71cd75. * update benchmark mode to simulation and python 3.12 * update benchmarks remove options * update benchmarks restore part of the options * update benchmarks restore part of the options * Revert "update benchmarks restore part of the options" This reverts commit 4917ebc. * Revert "update benchmarks restore part of the options" This reverts commit 2fe38dc. * Revert "update benchmarks remove options" This reverts commit 5fa3950. * Revert "update benchmark mode to simulation and python 3.12" This reverts commit 80e7ff3. * update benchmarks restore part of the options * run on codspeed-macro instead of ubuntu-latest * revert to ubuntu-latest for benchmarks and instrumentation mode * avoid begin if not in transaction, asyncio sleep every 100 rows for better performance
1 parent 95b9a97 commit 8c9f001

109 files changed

Lines changed: 2845 additions & 1771 deletions

File tree

Some content is hidden

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

.github/workflows/benchmark.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
- name: Install Poetry
2222
uses: snok/install-poetry@v1.4
2323
with:
24-
version: 1.8.4
24+
version: 2.1.3
2525
virtualenvs-create: false
2626

2727
- name: Poetry details

.github/workflows/deploy-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
- name: Install Poetry
2222
uses: snok/install-poetry@v1.4
2323
with:
24-
version: 1.8.4
24+
version: 2.1.3
2525
virtualenvs-create: false
2626
- name: Install dependencies
2727
run: |

.github/workflows/lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
- name: Install Poetry
2727
uses: snok/install-poetry@v1.4
2828
with:
29-
version: 1.8.4
29+
version: 2.1.3
3030
virtualenvs-create: false
3131

3232
- name: Poetry details

.github/workflows/python-publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
- name: Install Poetry
2626
uses: snok/install-poetry@v1.4
2727
with:
28-
version: 1.8.4
28+
version: 2.1.3
2929
virtualenvs-create: true
3030
virtualenvs-in-project: true
3131

.github/workflows/test-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
- name: Install Poetry
5555
uses: snok/install-poetry@v1.4
5656
with:
57-
version: 1.8.4
57+
version: 2.1.3
5858
virtualenvs-create: false
5959

6060
- name: Poetry details

.github/workflows/test_docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
- name: Install Poetry
2525
uses: snok/install-poetry@v1.4
2626
with:
27-
version: 1.8.4
27+
version: 2.1.3
2828
virtualenvs-create: false
2929
- name: Install dependencies
3030
run: |

.github/workflows/type-check.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
- name: Install Poetry
2727
uses: snok/install-poetry@v1.4
2828
with:
29-
version: 1.8.4
29+
version: 2.1.3
3030
virtualenvs-create: false
3131

3232
- name: Poetry details

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ profile.py
1818
*.db-journal
1919
*coverage.xml
2020
.benchmarks/
21+
CLAUDE.md

benchmarks/conftest.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ class Book(ormar.Model):
5050
create_test_database = init_tests(base_ormar_config, scope="function")
5151

5252

53+
@pytest_asyncio.fixture(autouse=True, scope="function")
54+
async def connect_database(create_test_database):
55+
if not base_ormar_config.database.is_connected:
56+
await base_ormar_config.database.connect()
57+
58+
yield
59+
60+
if base_ormar_config.database.is_connected:
61+
await base_ormar_config.database.disconnect()
62+
63+
5364
@pytest_asyncio.fixture
5465
async def author():
5566
author = await Author(name="Author", score=10).save()
@@ -79,14 +90,16 @@ async def authors_in_db(num_models: int):
7990
@pytest.mark.benchmark(
8091
min_rounds=1, timer=time.process_time, disable_gc=True, warmup=False
8192
)
82-
async def aio_benchmark(benchmark, event_loop: asyncio.BaseEventLoop):
93+
async def aio_benchmark(benchmark):
8394
def _fixture_wrapper(func):
8495
def _func_wrapper(*args, **kwargs):
8596
if asyncio.iscoroutinefunction(func):
97+
# Get the running event loop instead of requesting it as a fixture
98+
loop = asyncio.get_running_loop()
8699

87100
@benchmark
88101
def benchmarked_func():
89-
a = event_loop.run_until_complete(func(*args, **kwargs))
102+
a = loop.run_until_complete(func(*args, **kwargs))
90103
return a
91104

92105
return benchmarked_func

docs/fastapi/index.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ application.
3131
```python
3232
from typing import List, Optional, AsyncIterator
3333

34-
import databases
3534
import sqlalchemy
3635
from fastapi import FastAPI
3736

3837
import ormar
38+
from ormar import DatabaseConnection
3939

4040
from contextlib import asynccontextmanager
4141
from fastapi import FastAPI
@@ -55,7 +55,7 @@ def get_lifespan(config):
5555

5656
base_ormar_config = ormar.OrmarConfig(
5757
metadata=sqlalchemy.MetaData(),
58-
database=databases.Database("sqlite:///test.db"),
58+
database=DatabaseConnection("sqlite+aiosqlite:///test.db"),
5959
)
6060

6161
app = FastAPI(lifespan=get_lifespan(base_ormar_config))

0 commit comments

Comments
 (0)