async-orm-kit 1.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.
Files changed (92) hide show
  1. async_orm_kit/__init__.py +151 -0
  2. async_orm_kit/_logging.py +58 -0
  3. async_orm_kit/_version.py +1 -0
  4. async_orm_kit/config.py +31 -0
  5. async_orm_kit/exceptions.py +353 -0
  6. async_orm_kit/integrations/__init__.py +15 -0
  7. async_orm_kit/integrations/alembic.py +56 -0
  8. async_orm_kit/integrations/fastapi.py +134 -0
  9. async_orm_kit/integrations/storage.py +213 -0
  10. async_orm_kit/manager/__init__.py +3 -0
  11. async_orm_kit/manager/manager.py +568 -0
  12. async_orm_kit/models/__init__.py +3 -0
  13. async_orm_kit/models/base.py +568 -0
  14. async_orm_kit/models/fields/__init__.py +23 -0
  15. async_orm_kit/models/fields/exceptions.py +10 -0
  16. async_orm_kit/models/fields/typed/__init__.py +11 -0
  17. async_orm_kit/models/fields/typed/base.py +155 -0
  18. async_orm_kit/models/fields/typed/file.py +697 -0
  19. async_orm_kit/models/fields/typed/string.py +38 -0
  20. async_orm_kit/models/fields/validators.py +110 -0
  21. async_orm_kit/models/meta.py +181 -0
  22. async_orm_kit/models/mixins.py +19 -0
  23. async_orm_kit/observers/__init__.py +4 -0
  24. async_orm_kit/observers/mixin.py +26 -0
  25. async_orm_kit/observers/model_observer.py +20 -0
  26. async_orm_kit/observers/queryset_observer.py +38 -0
  27. async_orm_kit/py.typed +0 -0
  28. async_orm_kit/query/__init__.py +0 -0
  29. async_orm_kit/query/aggregations/__init__.py +8 -0
  30. async_orm_kit/query/aggregations/avg.py +71 -0
  31. async_orm_kit/query/aggregations/base.py +317 -0
  32. async_orm_kit/query/aggregations/count.py +115 -0
  33. async_orm_kit/query/aggregations/max.py +76 -0
  34. async_orm_kit/query/aggregations/min.py +76 -0
  35. async_orm_kit/query/aggregations/sum.py +73 -0
  36. async_orm_kit/query/compiler.py +574 -0
  37. async_orm_kit/query/debugger.py +269 -0
  38. async_orm_kit/query/expressions/__init__.py +62 -0
  39. async_orm_kit/query/expressions/analysis.py +56 -0
  40. async_orm_kit/query/expressions/case.py +321 -0
  41. async_orm_kit/query/expressions/collections.py +251 -0
  42. async_orm_kit/query/expressions/f.py +362 -0
  43. async_orm_kit/query/expressions/functions.py +202 -0
  44. async_orm_kit/query/expressions/subquery.py +206 -0
  45. async_orm_kit/query/expressions/value.py +101 -0
  46. async_orm_kit/query/expressions/window.py +95 -0
  47. async_orm_kit/query/lookups/__init__.py +121 -0
  48. async_orm_kit/query/lookups/conditions.py +315 -0
  49. async_orm_kit/query/lookups/correlated.py +86 -0
  50. async_orm_kit/query/lookups/json_paths.py +167 -0
  51. async_orm_kit/query/lookups/parser.py +276 -0
  52. async_orm_kit/query/lookups/resolver/__init__.py +5 -0
  53. async_orm_kit/query/lookups/resolver/context.py +150 -0
  54. async_orm_kit/query/lookups/resolver/resolver.py +572 -0
  55. async_orm_kit/query/lookups/resolver/types.py +150 -0
  56. async_orm_kit/query/mixins/__init__.py +0 -0
  57. async_orm_kit/query/mixins/combinable.py +376 -0
  58. async_orm_kit/query/mixins/orderable.py +208 -0
  59. async_orm_kit/query/observability.py +346 -0
  60. async_orm_kit/query/planning/__init__.py +0 -0
  61. async_orm_kit/query/planning/directives.py +117 -0
  62. async_orm_kit/query/planning/factory.py +40 -0
  63. async_orm_kit/query/planning/passes/__init__.py +15 -0
  64. async_orm_kit/query/planning/passes/base.py +47 -0
  65. async_orm_kit/query/planning/passes/cartesian_detection.py +74 -0
  66. async_orm_kit/query/planning/passes/depth_splitting.py +78 -0
  67. async_orm_kit/query/planning/passes/join_promotion.py +81 -0
  68. async_orm_kit/query/planning/passes/path_conflicts.py +103 -0
  69. async_orm_kit/query/planning/passes/redundant_path.py +67 -0
  70. async_orm_kit/query/planning/passes/strategy_selection.py +49 -0
  71. async_orm_kit/query/planning/planner.py +160 -0
  72. async_orm_kit/query/planning/protocols.py +78 -0
  73. async_orm_kit/query/postgres/__init__.py +0 -0
  74. async_orm_kit/query/postgres/optimizer.py +189 -0
  75. async_orm_kit/query/q.py +596 -0
  76. async_orm_kit/query/relations/__init__.py +0 -0
  77. async_orm_kit/query/relations/enums.py +16 -0
  78. async_orm_kit/query/relations/graph.py +908 -0
  79. async_orm_kit/query/relations/node.py +421 -0
  80. async_orm_kit/queryset/__init__.py +4 -0
  81. async_orm_kit/queryset/builder.py +1259 -0
  82. async_orm_kit/queryset/compound.py +379 -0
  83. async_orm_kit/queryset/executor.py +718 -0
  84. async_orm_kit/queryset/queryset.py +1726 -0
  85. async_orm_kit/queryset/state.py +164 -0
  86. async_orm_kit/queryset/validators.py +361 -0
  87. async_orm_kit/queryset/writer.py +755 -0
  88. async_orm_kit/types.py +23 -0
  89. async_orm_kit-1.0.0.dist-info/METADATA +318 -0
  90. async_orm_kit-1.0.0.dist-info/RECORD +92 -0
  91. async_orm_kit-1.0.0.dist-info/WHEEL +4 -0
  92. async_orm_kit-1.0.0.dist-info/licenses/LICENSE +21 -0
async_orm_kit/types.py ADDED
@@ -0,0 +1,23 @@
1
+ from datetime import date, datetime, time, timedelta
2
+ from decimal import Decimal
3
+ from typing import TYPE_CHECKING, TypeVar
4
+
5
+ if TYPE_CHECKING:
6
+ from async_orm_kit.models import Model
7
+ from async_orm_kit.queryset import QuerySet
8
+
9
+ ModelType = TypeVar("ModelType", bound="Model")
10
+ QS = TypeVar("QS", bound="QuerySet")
11
+
12
+ SAFE_SCALAR_TYPES = (
13
+ str,
14
+ int,
15
+ float,
16
+ bool,
17
+ type(None),
18
+ Decimal,
19
+ date,
20
+ datetime,
21
+ time,
22
+ timedelta,
23
+ )
@@ -0,0 +1,318 @@
1
+ Metadata-Version: 2.4
2
+ Name: async-orm-kit
3
+ Version: 1.0.0
4
+ Summary: Async-first Django-inspired QuerySets and relationship-aware query planning for SQLAlchemy
5
+ Keywords: async,asyncio,database,django-inspired,orm,queryset,sqlalchemy,query-planner,postgresql,mysql
6
+ Author: Aryan Niknezhad, Mehrshad Mirshekary
7
+ Author-email: Aryan Niknezhad <aryan513966@gmail.com>, Mehrshad Mirshekary <mehrshad_mirshekary@email.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Framework :: AsyncIO
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Programming Language :: Python :: 3.15
20
+ Classifier: Programming Language :: Python :: Implementation :: CPython
21
+ Classifier: Topic :: Database
22
+ Classifier: Topic :: Database :: Front-Ends
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Typing :: Typed
25
+ Requires-Dist: sqlalchemy[asyncio]>=2.0.40,<3.0
26
+ Requires-Dist: sphinx>=8.2,<10 ; extra == 'docs'
27
+ Requires-Dist: sphinx-rtd-theme>=3.0,<4 ; extra == 'docs'
28
+ Requires-Dist: fastapi>=0.110,<1.0 ; extra == 'fastapi'
29
+ Requires-Dist: alembic>=1.13,<2.0 ; extra == 'migrations'
30
+ Requires-Dist: asyncmy>=0.2,<1 ; extra == 'mysql'
31
+ Requires-Dist: cryptography>=44 ; extra == 'mysql'
32
+ Requires-Dist: asyncpg>=0.29,<1 ; extra == 'postgres'
33
+ Requires-Dist: aiosqlite>=0.20,<1 ; extra == 'sqlite'
34
+ Requires-Dist: async-storage-kit>=1.0.0,<2.0.0 ; extra == 'storage'
35
+ Requires-Dist: pytest>=8.3,<10 ; extra == 'test'
36
+ Requires-Dist: pytest-asyncio>=0.24,<2 ; extra == 'test'
37
+ Requires-Dist: pytest-cov>=6,<8 ; extra == 'test'
38
+ Requires-Dist: aiosqlite>=0.20,<1 ; extra == 'test'
39
+ Requires-Dist: async-storage-kit>=1.0.0,<2.0.0 ; extra == 'test'
40
+ Requires-Dist: alembic>=1.13,<2.0 ; extra == 'test'
41
+ Requires-Dist: fastapi>=0.110,<1.0 ; extra == 'test'
42
+ Requires-Dist: httpx>=0.27,<1 ; extra == 'test'
43
+ Requires-Python: >=3.11, <3.16
44
+ Project-URL: Homepage, https://github.com/Lazarus-org/async-orm-kit
45
+ Project-URL: Repository, https://github.com/Lazarus-org/async-orm-kit
46
+ Project-URL: Documentation, https://github.com/Lazarus-org/async-orm-kit/blob/main/docs/index.rst
47
+ Project-URL: Issues, https://github.com/Lazarus-org/async-orm-kit/issues
48
+ Project-URL: Changelog, https://github.com/Lazarus-org/async-orm-kit/blob/main/CHANGELOG.md
49
+ Provides-Extra: docs
50
+ Provides-Extra: fastapi
51
+ Provides-Extra: migrations
52
+ Provides-Extra: mysql
53
+ Provides-Extra: postgres
54
+ Provides-Extra: sqlite
55
+ Provides-Extra: storage
56
+ Provides-Extra: test
57
+ Description-Content-Type: text/markdown
58
+
59
+ # Async ORM Kit
60
+
61
+ [![PyPI version](https://img.shields.io/pypi/v/async-orm-kit?style=flat-square&logo=pypi&logoColor=white)](https://pypi.org/project/async-orm-kit/)
62
+ [![Python versions](https://img.shields.io/pypi/pyversions/async-orm-kit?style=flat-square&logo=python&logoColor=white)](https://pypi.org/project/async-orm-kit/)
63
+ [![License](https://img.shields.io/github/license/Lazarus-org/async-orm-kit?style=flat-square&color=blue)](LICENSE)
64
+
65
+ [![CI](https://github.com/Lazarus-org/async-orm-kit/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/Lazarus-org/async-orm-kit/actions/workflows/ci.yml)
66
+ [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-FAB040?style=flat-square&logo=precommit&logoColor=white)](.pre-commit-config.yaml)
67
+ [![Ruff](https://img.shields.io/badge/lint_%26_format-Ruff-D7FF64?style=flat-square&logo=ruff&logoColor=white)](https://docs.astral.sh/ruff/)
68
+ [![codecov](https://codecov.io/gh/lazarus-org/async-orm-kit/branch/main/graph/badge.svg)](https://codecov.io/gh/lazarus-org/async-orm-kit)
69
+ [![Typed](https://img.shields.io/badge/typing-py.typed-3776AB?style=flat-square)](src/async_orm_kit/py.typed)
70
+
71
+ [![API documentation](https://img.shields.io/badge/docs-API_reference-0078D4?style=flat-square&logo=readthedocs&logoColor=white)](docs/reference/index.rst)
72
+ [![Last commit](https://img.shields.io/github/last-commit/Lazarus-org/async-orm-kit?style=flat-square)](https://github.com/Lazarus-org/async-orm-kit/commits/main/)
73
+ [![Open issues](https://img.shields.io/github/issues/Lazarus-org/async-orm-kit?style=flat-square)](https://github.com/Lazarus-org/async-orm-kit/issues)
74
+
75
+ [![SQLAlchemy](https://img.shields.io/badge/SQLAlchemy-2.x-D71F00?style=flat-square)](https://www.sqlalchemy.org/)
76
+
77
+ **Django-inspired models, managers, expressions and QuerySets — powered by SQLAlchemy's async infrastructure.**
78
+
79
+ `async-orm-kit` gives you an expressive, chainable ORM query API while preserving SQLAlchemy 2.x mappings, drivers, sessions, transactions and composable SQL expressions. It's an **async-first library** for applications that want Django-style querying without adopting Django or losing SQLAlchemy control.
80
+
81
+ ```python
82
+ users = await (
83
+ User.objects.filter(session, active=True, age__gte=18)
84
+ .exclude(email__isnull=True)
85
+ .order_by("-created_at", "id")
86
+ .limit(20)
87
+ )
88
+ ```
89
+
90
+ ## Features
91
+
92
+ | Area | Capabilities |
93
+ | --- | --- |
94
+ | **Models & managers** | SQLAlchemy declarative models, default/custom managers, model validation, serialization helpers, model-specific exceptions |
95
+ | **QuerySets** | Lazy immutable chaining, `filter`, `exclude`, `get`, `first`, `count`, `exists`, projections, ordering, pagination, async streaming |
96
+ | **Lookups & logic** | `Q` AND/OR/NOT, field and relationship traversal, NULL handling, nested JSON path lookups |
97
+ | **Expressions** | `F`, `Value`, `Case`/`When`, arithmetic and atomic SQL updates, typed SQL functions |
98
+ | **Aggregations** | `Count`, `Sum`, `Avg`, `Min`, `Max`, grouped annotations, `HAVING`, filtered and custom aggregates |
99
+ | **Advanced SQL** | `Subquery`, nested `OuterRef`, `Exists`, window functions, `UNION` / `INTERSECT` / `EXCEPT`, CTEs and recursive CTEs |
100
+ | **Relationships** | `select_related`, `prefetch_related`, relationship planning, correlated collection exclusions, related-row counts |
101
+ | **Database writes** | Create/update/delete, bulk operations, conflict handling, generated defaults, transaction-aware lifecycle hooks |
102
+ | **PostgreSQL** | JSONB and ARRAY operators, row-lock options and dialect-specific upserts |
103
+ | **Extensibility** | QuerySet-local custom lookups, trusted SQL function/aggregate factories, deferred fields, keyset pagination |
104
+ | **Observability** | Event-backed `QueryProfiler`, SQL timings, task-scoped captures, bounded history, heuristic N+1 detection |
105
+ | **Integrations** | Optional `async-storage-kit` / `FileField`, Alembic and FastAPI adapters |
106
+
107
+ The design is intentionally **session-explicit, transaction-neutral and SQLAlchemy-native**. QuerySet methods don't hide network connections, migrations, commits or rollbacks.
108
+
109
+ ## Installation
110
+
111
+ **Requirements:** CPython 3.11–3.15, SQLAlchemy 2.x and a compatible async database driver. Only SQLAlchemy is a mandatory runtime dependency.
112
+
113
+ ```bash
114
+ # Install the source checkout with SQLite support
115
+ python -m pip install -e ".[sqlite]"
116
+
117
+ # Distribution extras, when a published build is available:
118
+ pip install "async-orm-kit[postgres]" # asyncpg
119
+ pip install "async-orm-kit[mysql]" # asyncmy
120
+ pip install "async-orm-kit[storage]" # async-storage-kit
121
+ pip install "async-orm-kit[migrations]" # Alembic
122
+ pip install "async-orm-kit[fastapi]" # FastAPI
123
+ ```
124
+
125
+ SQLite uses `aiosqlite`; PostgreSQL uses `asyncpg`; MySQL uses `asyncmy`. The package does not start a database or configure a connection pool for you. See [Installation](docs/installation.rst) and the [database compatibility matrix](docs/compatibility.rst).
126
+
127
+ ## Quick start
128
+
129
+ Define models with familiar SQLAlchemy mapping primitives:
130
+
131
+ ```python
132
+ from sqlalchemy import Boolean, ForeignKey, String
133
+ from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
134
+ from sqlalchemy.orm import Mapped, mapped_column, relationship
135
+
136
+ from async_orm_kit import Model
137
+
138
+ engine = create_async_engine("sqlite+aiosqlite:///./app.db")
139
+ SessionFactory = async_sessionmaker(engine, expire_on_commit=False)
140
+
141
+
142
+ class Author(Model):
143
+ __tablename__ = "authors"
144
+
145
+ id: Mapped[int] = mapped_column(primary_key=True)
146
+ name: Mapped[str] = mapped_column(String(120))
147
+ active: Mapped[bool] = mapped_column(Boolean, default=True)
148
+ posts: Mapped[list["Post"]] = relationship(back_populates="author")
149
+
150
+
151
+ class Post(Model):
152
+ __tablename__ = "posts"
153
+
154
+ id: Mapped[int] = mapped_column(primary_key=True)
155
+ author_id: Mapped[int] = mapped_column(ForeignKey("authors.id"))
156
+ title: Mapped[str] = mapped_column(String(255))
157
+ view_count: Mapped[int] = mapped_column(default=0)
158
+ author: Mapped[Author] = relationship(back_populates="posts")
159
+ ```
160
+
161
+ In a disposable development database you can create tables through SQLAlchemy. For deployed applications, use reviewed Alembic migrations:
162
+
163
+ ```python
164
+ async with engine.begin() as connection:
165
+ await connection.run_sync(Model.metadata.create_all)
166
+ ```
167
+
168
+ Write through the caller-owned transaction:
169
+
170
+ ```python
171
+ async with SessionFactory() as session:
172
+ async with session.begin():
173
+ author = await Author.objects.create(session, name="Ada")
174
+ await Post.objects.create(session, author_id=author.id, title="Async SQL")
175
+ ```
176
+
177
+ Query with eager loading and normal `AsyncSession` ownership:
178
+
179
+ ```python
180
+ async with SessionFactory() as session:
181
+ authors = await (
182
+ Author.objects.filter(session, active=True)
183
+ .prefetch_related("posts")
184
+ .order_by("name")
185
+ )
186
+
187
+ for author in authors:
188
+ print(author.name, len(author.posts))
189
+ ```
190
+
191
+ **Important:** Manager methods accept `session` as their **first argument**. A QuerySet remembers that session; chaining methods such as `.filter(...)` and `.order_by(...)` do **not** take it again. Alternatively, `Author.objects.using(session)` returns a session-bound manager proxy.
192
+
193
+ ## Querying and expressions
194
+
195
+ ### Boolean logic, aggregation and atomic updates
196
+
197
+ ```python
198
+ from async_orm_kit import Count, F, Q, Sum
199
+
200
+ # Boolean predicates and relationship traversal
201
+ query = Author.objects.filter(
202
+ session,
203
+ Q(name__icontains="ada") | Q(posts__title__icontains="sql"),
204
+ )
205
+
206
+ # Count related rows, preserving parents with no related records
207
+ ranked = await (
208
+ Author.objects.annotate(session, post_count=Count("posts"))
209
+ .filter(post_count__gte=1)
210
+ .order_by("-post_count")
211
+ )
212
+
213
+ # Updates use SQL-side expressions and still require an application transaction.
214
+ async with SessionFactory() as write_session:
215
+ async with write_session.begin():
216
+ await Post.objects.filter(write_session, id=42).update(
217
+ view_count=F("view_count") + 1
218
+ )
219
+ ```
220
+
221
+ Use `values(...).annotate(...)` for grouped summaries and `aggregate(...)` for a terminal summary dictionary. Complex combinations of aggregate annotations and row predicates support `Q` OR/AND/NOT using correlated existence semantics. See [Aggregations](docs/advanced/aggregation.rst) and [Expressions](docs/advanced/expressions.rst).
222
+
223
+ ### Subqueries, set operations and JSON
224
+
225
+ ```python
226
+ from async_orm_kit import Exists, OuterRef
227
+
228
+ matching = Post.objects.filter(
229
+ session, author_id=OuterRef("id"), title__icontains="async"
230
+ )
231
+ authors = await Author.objects.filter(session, Exists(matching))
232
+
233
+ # Set operations on compatible projections and the same session
234
+ first = Author.objects.filter(session, active=True).values("id", "name")
235
+ second = Author.objects.filter(session, name__startswith="A").values("id", "name")
236
+ selected = await first.union(second).filter(name__icontains="a").order_by("id")
237
+
238
+ # For a model with a mapped SQLAlchemy JSON column named payload:
239
+ # events = await Event.objects.filter(session, payload__profile__age__gte=18)
240
+ ```
241
+
242
+ The package also supports typed `JSONPath`, PostgreSQL JSONB/ARRAY expressions, CTEs, window functions and SQLAlchemy-composable subqueries. Dialect-specific operators are not silently emulated with text matching. See [Advanced SQL](docs/advanced/sets-cte.rst), [JSON & ARRAY](docs/advanced/json-array.rst) and [Correlated subqueries](docs/advanced/subqueries.rst).
243
+
244
+ ### Pagination and streaming
245
+
246
+ ```python
247
+ base = Author.objects.order_by(session, "id")
248
+ first_page = await base.limit(25)
249
+
250
+ if first_page:
251
+ next_page = await base.seek_after(first_page[-1].id).limit(25)
252
+
253
+ async for author in base.stream():
254
+ process(author)
255
+ ```
256
+
257
+ Keyset pagination requires a deterministic non-nullable ordering that includes the primary key. It accepts **cursor values**, not an opaque signed token. Keep the session open throughout streaming. See [Pagination](docs/advanced/pagination.rst).
258
+
259
+ ## Transactions and integrations
260
+
261
+ ### You own the session and transaction
262
+
263
+ ```python
264
+ async with SessionFactory() as session:
265
+ async with session.begin():
266
+ await Author.objects.create(session, name="Grace")
267
+ ```
268
+
269
+ Model and QuerySet mutation methods flush or execute SQL **without committing or rolling back**. A failed flush requires rollback before session reuse. Sessions must not be shared across concurrent tasks. Model `post_save` and `post_delete` observers run after flush, **before commit**; they aren't after-commit hooks.
270
+
271
+ ### Optional framework and storage integrations
272
+
273
+ - **[FastAPI](docs/integrations-rst/fastapi.rst):** request-scoped `AsyncSession` dependency, explicit application transactions and safe exception responses.
274
+ - **[Alembic](docs/integrations-rst/alembic.rst):** import model metadata for autogeneration; schema migrations remain application-owned.
275
+ - **[FileField / async-storage-kit](docs/integrations-rst/storage.rst):** asynchronous upload, streaming download, metadata and backend adapters. Object storage is **not** transactionally coupled to the database.
276
+ - **[Observability](docs/advanced/observability.rst):** SQLAlchemy-event query timing, bounded execution traces and suspected N+1 patterns.
277
+
278
+ ## Documentation
279
+
280
+ The primary documentation is authored in **reStructuredText** and built with Sphinx. Start at [`docs/index.rst`](docs/index.rst), or open the sections directly:
281
+
282
+ | Getting started | ORM fundamentals | Advanced queries | Operations |
283
+ | --- | --- | --- | --- |
284
+ | [Install](docs/installation.rst) | [Models](docs/guide/models.rst) | [Expressions](docs/advanced/expressions.rst) | [Compatibility](docs/compatibility.rst) |
285
+ | [Quick start](docs/quickstart.rst) | [Managers](docs/guide/managers.rst) | [Aggregations](docs/advanced/aggregation.rst) | [Troubleshooting](docs/guide/troubleshooting.rst) |
286
+ | [Design](docs/introduction.rst) | [QuerySets](docs/guide/querysets.rst) | [Subqueries](docs/advanced/subqueries.rst) | [Development](docs/maintainers/development.rst) |
287
+ | [Sessions](docs/guide/sessions.rst) | [Relationships](docs/guide/relationships.rst) | [Set operations & CTEs](docs/advanced/sets-cte.rst) | [Release policy](docs/maintainers/release.rst) |
288
+
289
+ The [complete API reference](docs/reference/index.rst) documents exported classes, methods, functions, exceptions, integrations and custom expression types. Supporting architecture decisions are in `docs/architecture/ADR/`.
290
+
291
+ ### Build locally
292
+
293
+ ```bash
294
+ python -m pip install -e ".[docs]"
295
+ sphinx-build -b html -W --keep-going docs docs/_build/html
296
+ ```
297
+
298
+ The repository also supplies `.readthedocs.yaml` for hosted Sphinx builds.
299
+
300
+ ## Development and quality
301
+
302
+ ```bash
303
+ uv lock --check
304
+ uv sync --locked
305
+ uv run pytest -q
306
+ uv run ruff check src tests .github/scripts
307
+ uv run ruff format --check src tests .github/scripts
308
+ uv run mypy src/async_orm_kit
309
+ uv run bandit -c pyproject.toml -r src/async_orm_kit
310
+ ```
311
+
312
+ The source includes offline SQL correctness tests and native-driver integration suites for `aiosqlite`, `asyncpg` and `asyncmy`. A skipped provider test is **not** passing compatibility evidence. Before the first stable release, the supported Python/OS matrix, live database tests, security/type checks, distributions and documentation build must all be verified. See [Release readiness](docs/maintainers/release.rst).
313
+
314
+ ## Contributing, security and licensing
315
+
316
+ Contributions and community conduct are governed by the existing detailed [CONTRIBUTING.md](CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) documents. Report security issues using [SECURITY.md](SECURITY.md), rather than public issues. Release notes are in [CHANGELOG.md](CHANGELOG.md).
317
+
318
+ Async ORM Kit is licensed under the [MIT License](LICENSE).
@@ -0,0 +1,92 @@
1
+ async_orm_kit/__init__.py,sha256=bQR8PPs6FiBT9TCmGCQudhpdEFsLYC6DdP5WFq4k6fo,3273
2
+ async_orm_kit/_logging.py,sha256=3a18wzmZeg_JVEaubmtekw6d7o9WTEf1iTPF2u0UWi4,2027
3
+ async_orm_kit/_version.py,sha256=J-j-u0itpEFT6irdmWmixQqYMadNl1X91TxUmoiLHMI,22
4
+ async_orm_kit/config.py,sha256=6TTXkCF3vHqxTus5lVd4hse50SE5_2siciLIWCJfkgs,955
5
+ async_orm_kit/exceptions.py,sha256=ew2_hBv2sGlDhiL_nvmWhO1NfRqb8uBlOtdbVG58kcw,13487
6
+ async_orm_kit/integrations/__init__.py,sha256=QcJOG_xQFVvK2qlLX-PaNivWaYoHMQTSylwVEFzRO3g,446
7
+ async_orm_kit/integrations/alembic.py,sha256=I7ds1SxUKjR1m9Hegwjm47oMrEpNDAR4dIYg0IgXqWw,2028
8
+ async_orm_kit/integrations/fastapi.py,sha256=znQjiXcSZnuDQwrTjn06VW2fPDbPhhMBozdYBW_A4Ws,4822
9
+ async_orm_kit/integrations/storage.py,sha256=NnD31AxKk2oC66IdpoUokka_Uew7twSRk8aSXBvPF4I,7753
10
+ async_orm_kit/manager/__init__.py,sha256=xrUzRNQTTaW4tt4R8IsZQq382aU9GxSclCOwIZuQIoQ,52
11
+ async_orm_kit/manager/manager.py,sha256=4JoqvwHMFuDb7NNvHii-xkM7wk0ArnLDrPRhN6NCBxg,21884
12
+ async_orm_kit/models/__init__.py,sha256=F6gddCdrPE2KHkNmapH_Iv-GKeBCOfJfgBEo0G69e04,45
13
+ async_orm_kit/models/base.py,sha256=SHQ03fdFDPch3hxkVKUz-63Rv-lgaU7PwqpyIlDeYFY,20700
14
+ async_orm_kit/models/fields/__init__.py,sha256=saywUj22r9rnm8vl5HvxbdUJjTqSktqME8kT_8U90CM,510
15
+ async_orm_kit/models/fields/exceptions.py,sha256=U7HW-BGs_stu-qXWZPZ9f5aZioYnD6gT3nfc6RnsEmg,310
16
+ async_orm_kit/models/fields/typed/__init__.py,sha256=0jMFqTQ2TPzrqbeyVe5TNvih74p3RFPE1K2Imx59S50,236
17
+ async_orm_kit/models/fields/typed/base.py,sha256=8MeLJDMH1jwJ49sJ5207OGNhQrxZFpkewh59RK2wZJQ,5073
18
+ async_orm_kit/models/fields/typed/file.py,sha256=5WyfMOVnIDhxJkyXvXME4MgoX2XsQf_XuB_6szZsRlI,25602
19
+ async_orm_kit/models/fields/typed/string.py,sha256=cceV1z4IIFWFUgiR-OR_fiGCps96xpH9GsC_A-KGsLI,1114
20
+ async_orm_kit/models/fields/validators.py,sha256=PcPYYbCZx092NJR-6toCn3hPDNdDmA6GTBpWTSKq9hg,3442
21
+ async_orm_kit/models/meta.py,sha256=4ggjADPQuzgpN-Udqv2PTkodCd0-b1GB-h2aAcqGAvQ,7190
22
+ async_orm_kit/models/mixins.py,sha256=G6vgXZqoLagDj7MPXCBdn7ml35Zjc-Fi_9v3XqKzHa8,744
23
+ async_orm_kit/observers/__init__.py,sha256=qW2niOIUfGXDQ0NIPIQeJ14Wx8Arr3SK9S4_If0Sd1U,155
24
+ async_orm_kit/observers/mixin.py,sha256=diWQSkeHJBfpVejTT2rz78pY-Khq0sareWkNCaahrF8,855
25
+ async_orm_kit/observers/model_observer.py,sha256=H_WevHj8dHBMayAaVDqUa-Zmab22_DdHyBmXct8KjFk,527
26
+ async_orm_kit/observers/queryset_observer.py,sha256=PYDzxQzz-xtMjoavK-LP4vH0bb3-vQWvlklZMlkzmeA,1040
27
+ async_orm_kit/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
+ async_orm_kit/query/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
+ async_orm_kit/query/aggregations/__init__.py,sha256=gi18bHwBjQk3wS1dXnbE7wqbu-QZx4lo6EIZ3_i_cYk,239
30
+ async_orm_kit/query/aggregations/avg.py,sha256=09lKi74JUGJO5GPMfZ4Db4Vfsf80Ef_Ykx9oYLTBw4g,2936
31
+ async_orm_kit/query/aggregations/base.py,sha256=fswtU07-CejU2rdn2wdha8bF08Kocw0QJ5RsNibP62Y,14977
32
+ async_orm_kit/query/aggregations/count.py,sha256=SVYObnXXX2kc9mg90VXBWkv1MfwAe7nYMaWsibyVNX8,4712
33
+ async_orm_kit/query/aggregations/max.py,sha256=8Jk_pY0C42C9XcV6Ia_WMbpq9FHX06Cm20TmUxzpcB4,3141
34
+ async_orm_kit/query/aggregations/min.py,sha256=woh9AyvfE6X1zFbvWtAM8Nf2da7o28ToFtUnq-xYrvs,3140
35
+ async_orm_kit/query/aggregations/sum.py,sha256=73y-vrQ0-1Eoi6zEIwPX5-6lesaAu1MHb0PdznPuY7A,3093
36
+ async_orm_kit/query/compiler.py,sha256=nF4LcjiLAZ11HEt5lhV9R4DNuptSSnKOG14fwTcBPq0,22674
37
+ async_orm_kit/query/debugger.py,sha256=bx4ERdnp5zHL-nrfJ1_VVXxg5F6cr7eGt3g1ppYJ4mM,9165
38
+ async_orm_kit/query/expressions/__init__.py,sha256=s7UjRe7fYWV3pgrAPhRSdnYF4g5bL4UdzLn8ALJ4RZs,986
39
+ async_orm_kit/query/expressions/analysis.py,sha256=IQHoip8mwkiURDdioCGj3s_XrTIRU4jgSB1Q7jduNQA,1975
40
+ async_orm_kit/query/expressions/case.py,sha256=XoLV8WDBvhKvwl9xJ15Rf_wdnLNuXSRzuMtv4xx4B4Y,10934
41
+ async_orm_kit/query/expressions/collections.py,sha256=tVrnLdBsAKZKDcNFyTvZ5caUnbCnW0nJVT34_mvjPzg,9142
42
+ async_orm_kit/query/expressions/f.py,sha256=9dUsT2k_RRFfSj-vb1SGbwpnFhx2e6Yecb0hp3FiJrI,13750
43
+ async_orm_kit/query/expressions/functions.py,sha256=-uiSSvPM2e7ga-RHjAs0f1w-AffJ4LfciMPvXDGeFA4,6783
44
+ async_orm_kit/query/expressions/subquery.py,sha256=FfjwVHK3qfzljDwjOYmnx0CJVb82kHTOF6qYdpfOK38,8787
45
+ async_orm_kit/query/expressions/value.py,sha256=-DCworcAQPja9IixPGkR3BttMIYCmOzd96Tem51OBYI,4042
46
+ async_orm_kit/query/expressions/window.py,sha256=7eLZPYVRpKYTjIb0_TVrdYTMWp8UTjCC-Hd6Dt_yorU,3604
47
+ async_orm_kit/query/lookups/__init__.py,sha256=DdQT_cq9aweAIEhRhs2qLqIK3qbz0vfwKgzjRPUfMwI,4044
48
+ async_orm_kit/query/lookups/conditions.py,sha256=_Y6r1OZE7T5g4Ip96jdOZRRnILo3ZAhTCUxcclnV6-Y,13826
49
+ async_orm_kit/query/lookups/correlated.py,sha256=KXTFBHOU1fKbO5fb41az34vxpseW6cNm-id2MNia7Ds,3283
50
+ async_orm_kit/query/lookups/json_paths.py,sha256=fJd9qEOlWvtAo_nlPMMeB9o36siXHeBCYeVqZZM6B0c,6690
51
+ async_orm_kit/query/lookups/parser.py,sha256=8wcMjC6Brto0con6FehkF0xKxsZ9T0qz-NAXQ_lR9Us,12590
52
+ async_orm_kit/query/lookups/resolver/__init__.py,sha256=0uBjLvzMRLK_IyB_XbjG7hkikY9elVb-Zx8Y4r0ftXA,209
53
+ async_orm_kit/query/lookups/resolver/context.py,sha256=rNdwXP9vxISylcS_Jx_RQlkHOGzgQjGp0HG1zD5yGCY,6880
54
+ async_orm_kit/query/lookups/resolver/resolver.py,sha256=ceM1H0vya4RDjuXWMODjBz-sgAZME_6n4T4tWlZLvz8,24910
55
+ async_orm_kit/query/lookups/resolver/types.py,sha256=zmsbIGFzYHsfDvVPhhpHDzH_JsfWsAnVDR9P6VwPY9E,6017
56
+ async_orm_kit/query/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
+ async_orm_kit/query/mixins/combinable.py,sha256=rGOwxnJpwUytm0w9VORJSwVQ_bHatxyra5kWasZbIpc,14417
58
+ async_orm_kit/query/mixins/orderable.py,sha256=B3qXmBSaEXXaKJJRgdDXMm-ir8k-aJRc7z_TmoFThls,8895
59
+ async_orm_kit/query/observability.py,sha256=yWK4mU-hdXQMAEbPQkIz27aZ97nqVnT5er_tuQ_TgRw,12979
60
+ async_orm_kit/query/planning/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
+ async_orm_kit/query/planning/directives.py,sha256=d3Vc6jx9lQEuPp4WoLWU_KvO71HIZUKHHYa7gHbp8X0,4191
62
+ async_orm_kit/query/planning/factory.py,sha256=2FTg_VQVm5I7htHDR6YZTU-cvLFMkG5f_JapaskWQj4,1254
63
+ async_orm_kit/query/planning/passes/__init__.py,sha256=GScNSxzfV9AmapHZ9XsRkdvOOKHUPtBhyrygYdasujQ,485
64
+ async_orm_kit/query/planning/passes/base.py,sha256=phErPZpdvydcTWd2hebc2Vm7GxfRohOILygQjCMKmjQ,1237
65
+ async_orm_kit/query/planning/passes/cartesian_detection.py,sha256=e53On7uh3JXbqBebTTukprYttVl_ktZZiTXEoPVOa_M,2504
66
+ async_orm_kit/query/planning/passes/depth_splitting.py,sha256=j07eyt6l3JNe8PVoIWsrqouqR7qhmPifBeU-fMVidaQ,2737
67
+ async_orm_kit/query/planning/passes/join_promotion.py,sha256=r8Pbhk6fBM6TvcIjoAFJIRaMfiJA9DgOiSc2NWz16c8,2595
68
+ async_orm_kit/query/planning/passes/path_conflicts.py,sha256=pCpnCf8jedWDFAVKE5lKC3_cA-t0OoKApJnj7jBQzIA,3926
69
+ async_orm_kit/query/planning/passes/redundant_path.py,sha256=9yMMqNvzZ_dskplVKv92NOGq0r657aiUA_VUg85Burw,2322
70
+ async_orm_kit/query/planning/passes/strategy_selection.py,sha256=Qk9ZXWPfOxyvbC0ZW7ROhQ8udI21iFxBw_0iw0jRImE,1601
71
+ async_orm_kit/query/planning/planner.py,sha256=2W-34LOQL223Gq_zfo2JOxQbss3Jaq9UJAfqm3u0W5Y,5482
72
+ async_orm_kit/query/planning/protocols.py,sha256=nolSkVKcvNAp7WvjT2mevCyPT5rNPPn1C_XM3cCDWJQ,1811
73
+ async_orm_kit/query/postgres/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
+ async_orm_kit/query/postgres/optimizer.py,sha256=_-doCZOWY_A48t9GRz7K0t8DsmmbKGCgXZUc6-ggvBA,5955
75
+ async_orm_kit/query/q.py,sha256=UvHeLKzckbUuLjbJUgGW4wpA5-wQTSeNvmwhgpPpdbo,23011
76
+ async_orm_kit/query/relations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
+ async_orm_kit/query/relations/enums.py,sha256=T0KAe3w3Ffo7SEsKyPAUw-3T786Gd5QowamupTarkhw,302
78
+ async_orm_kit/query/relations/graph.py,sha256=PAwKScKpcwK-T9k8xaSqB-K_32DhvUtpKBaUa15gp14,33996
79
+ async_orm_kit/query/relations/node.py,sha256=wHGF8jIXj-b4YI3zeQN2ZRKo4SiQn0w_8nn8kw8oFNs,16371
80
+ async_orm_kit/queryset/__init__.py,sha256=MlxV5oJjSTuorDGTAN7VGCnrS5CsGG7W55MQhbGTCCM,114
81
+ async_orm_kit/queryset/builder.py,sha256=JuF8rodWe-p1woYPZjnxrfFG5JZxedGYG40izhDdfmo,51966
82
+ async_orm_kit/queryset/compound.py,sha256=vmoaeBq7G1oLz-jDno4yrmVK32cOQBBOt3wbmfxFe30,15212
83
+ async_orm_kit/queryset/executor.py,sha256=uN_CSSnmb_sdvbfZhxeoQ3ZcRapImgHS1nFkPTjHjk0,29926
84
+ async_orm_kit/queryset/queryset.py,sha256=FgzmwrIrQ4NU_SXzU0PGMtbNfoFAGT7QbwcQvtvKKuM,68575
85
+ async_orm_kit/queryset/state.py,sha256=_7rrKAyTo9mt41hpmoo-EoZM-yb0P-7nH-dHaQYirb0,7670
86
+ async_orm_kit/queryset/validators.py,sha256=aPO_tqZ7GYCMaGh2O47aucPJ-w9u-VlCueo-luydckw,17065
87
+ async_orm_kit/queryset/writer.py,sha256=rfGwF1CxqKGtQrjKx7Z8x0vjuwFytrLjOHMmP7Y1MbI,32434
88
+ async_orm_kit/types.py,sha256=juglsMGfUzah7_i5OuIx9WclRdiJ-xPlLikzbiQBVFQ,461
89
+ async_orm_kit-1.0.0.dist-info/licenses/LICENSE,sha256=3xVqY2F_FE9nMl8iT4dxe25AlpFVwmzr4dLZQJ-T67w,1104
90
+ async_orm_kit-1.0.0.dist-info/WHEEL,sha256=MWx7psoF7KNST9G72pGtiBYuaXRXQXBk9pw5R6FzYko,80
91
+ async_orm_kit-1.0.0.dist-info/METADATA,sha256=II2b2XSw0C8TR1L7haDHiUcJEDN17uNrM4zXOTDpy8s,16446
92
+ async_orm_kit-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.13.7
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Async ORM Kit contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.