diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e340e3..51aa500 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ + `sqlalchemy`: add `unbound_fk()`, `bound_fk()` + Add `sqlalchemy_async` module with `SQLAlchemy()` async database binding. * Supports being used as an async context manager + * Automatically handles commit and rollback ++ `sqlalchemy_async` also offers `async_query()` ++ Changed `sqlalchemy.parent_children()` to use `lazy='selectin'` by default + Add `timed_cache()`, `TimedDict()`, `none_pass()`, `twocolon_list()`, `quote_css_string()`, `must_be()` + Add module `calendar` with `want_*` date type conversion utilities and `age_and_days()` + Move obsolete stuff to `obsolete` package (includes configparse 0.3 as of now) diff --git a/src/suou/redact.py b/src/suou/redact.py index e8ee104..cef86e7 100644 --- a/src/suou/redact.py +++ b/src/suou/redact.py @@ -1,5 +1,19 @@ """ "Security through obscurity" helpers for less sensitive logging + +NEW 0.5.0 + +--- + +Copyright (c) 2025 Sakuragasaki46. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +See LICENSE for the specific language governing permissions and +limitations under the License. + +This software is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ import re diff --git a/src/suou/sqlalchemy_async.py b/src/suou/sqlalchemy_async.py index b361046..575f239 100644 --- a/src/suou/sqlalchemy_async.py +++ b/src/suou/sqlalchemy_async.py @@ -1,5 +1,7 @@ """ -Helpers for asynchronous user of SQLAlchemy +Helpers for asynchronous use of SQLAlchemy. + +NEW 0.5.0 --- @@ -15,6 +17,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. """ from __future__ import annotations +from functools import wraps from sqlalchemy import Engine, Select, func, select @@ -150,4 +153,23 @@ class AsyncSelectPagination(Pagination): for i in self.items: yield i -__all__ = ('SQLAlchemy', ) \ No newline at end of file + +def async_query(db: SQLAlchemy, multi: False): + """ + Wraps a query returning function into an executor coroutine. + + The query function remains available as the .q or .query attribute. + """ + def decorator(func): + @wraps(func) + async def executor(*args, **kwargs): + async with db as session: + result = await session.execute(func(*args, **kwargs)) + return result.scalars() if multi else result.scalar() + executor.query = executor.q = func + return executor + return decorator + + +# Optional dependency: do not import into __init__.py +__all__ = ('SQLAlchemy', 'async_query') \ No newline at end of file