pyoq-sql 1.0.2__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.
- pyoq/__init__.py +10 -0
- pyoq/__main__.py +5 -0
- pyoq/_native.pyi +5 -0
- pyoq/cli/__init__.py +5 -0
- pyoq/cli/commands.py +270 -0
- pyoq/cli/defaults.py +98 -0
- pyoq/cli/services.py +97 -0
- pyoq/config/__init__.py +31 -0
- pyoq/config/connection.py +161 -0
- pyoq/config/loader.py +289 -0
- pyoq/config/models.py +245 -0
- pyoq/config/values.py +142 -0
- pyoq/descriptors.py +165 -0
- pyoq/diagnostics/__init__.py +68 -0
- pyoq/diagnostics/budget.py +136 -0
- pyoq/diagnostics/events.py +137 -0
- pyoq/diagnostics/fingerprint.py +267 -0
- pyoq/diagnostics/instrumented.py +237 -0
- pyoq/diagnostics/metrics.py +61 -0
- pyoq/diagnostics/observation.py +227 -0
- pyoq/diagnostics/scoped.py +103 -0
- pyoq/django/__init__.py +15 -0
- pyoq/django/apps.py +17 -0
- pyoq/django/execution.py +317 -0
- pyoq/django/generation.py +59 -0
- pyoq/django/management/__init__.py +0 -0
- pyoq/django/management/commands/__init__.py +0 -0
- pyoq/django/management/commands/makemigrations.py +53 -0
- pyoq/django/management/commands/pyoq_codegen.py +75 -0
- pyoq/django/parameters.py +101 -0
- pyoq/django/schema.py +379 -0
- pyoq/django/settings.py +87 -0
- pyoq/django/timeouts.py +105 -0
- pyoq/dsl/__init__.py +64 -0
- pyoq/dsl/aio/__init__.py +31 -0
- pyoq/dsl/aio/context.py +295 -0
- pyoq/dsl/aio/queries.py +335 -0
- pyoq/dsl/aio/writes.py +368 -0
- pyoq/dsl/context.py +326 -0
- pyoq/dsl/entry.py +37 -0
- pyoq/dsl/labels.py +36 -0
- pyoq/dsl/queries.py +339 -0
- pyoq/dsl/result.py +164 -0
- pyoq/dsl/writes.py +360 -0
- pyoq/errors.py +317 -0
- pyoq/fastapi/__init__.py +32 -0
- pyoq/fastapi/dependencies.py +167 -0
- pyoq/fastapi/lifespan.py +119 -0
- pyoq/fetching/__init__.py +55 -0
- pyoq/fetching/collections.py +136 -0
- pyoq/fetching/execution.py +587 -0
- pyoq/fetching/joined.py +79 -0
- pyoq/fetching/nesting.py +183 -0
- pyoq/fetching/plans.py +541 -0
- pyoq/fetching/select_in.py +149 -0
- pyoq/fetching/tables.py +110 -0
- pyoq/generation/__init__.py +54 -0
- pyoq/generation/cleanup.py +44 -0
- pyoq/generation/contracts.py +248 -0
- pyoq/generation/drift.py +169 -0
- pyoq/generation/lock.py +33 -0
- pyoq/generation/manifest.py +114 -0
- pyoq/generation/model.py +1001 -0
- pyoq/generation/pipeline.py +119 -0
- pyoq/generation/rendering/__init__.py +5 -0
- pyoq/generation/rendering/domains.py +51 -0
- pyoq/generation/rendering/enums.py +29 -0
- pyoq/generation/rendering/exports.py +70 -0
- pyoq/generation/rendering/imports.py +63 -0
- pyoq/generation/rendering/package.py +56 -0
- pyoq/generation/rendering/relations.py +133 -0
- pyoq/generation/rendering/routines.py +396 -0
- pyoq/generation/rendering/rows.py +79 -0
- pyoq/generation/rendering/source.py +121 -0
- pyoq/generation/rendering/tables.py +300 -0
- pyoq/generation/rendering/writes.py +514 -0
- pyoq/generation/validation.py +27 -0
- pyoq/generation/writer.py +184 -0
- pyoq/hydration/__init__.py +24 -0
- pyoq/hydration/engine.py +155 -0
- pyoq/hydration/identity.py +194 -0
- pyoq/hydration/plan.py +116 -0
- pyoq/migrations/__init__.py +9 -0
- pyoq/migrations/alembic.py +106 -0
- pyoq/migrations/hooks.py +75 -0
- pyoq/naming.py +261 -0
- pyoq/policies/__init__.py +47 -0
- pyoq/policies/bypass.py +122 -0
- pyoq/policies/governed.py +430 -0
- pyoq/policies/model.py +242 -0
- pyoq/policies/rewriting.py +263 -0
- pyoq/py.typed +1 -0
- pyoq/query/__init__.py +312 -0
- pyoq/query/aggregates.py +172 -0
- pyoq/query/arrays.py +65 -0
- pyoq/query/binding.py +52 -0
- pyoq/query/capabilities.py +317 -0
- pyoq/query/casts.py +73 -0
- pyoq/query/choices.py +185 -0
- pyoq/query/decoding.py +360 -0
- pyoq/query/documents.py +56 -0
- pyoq/query/execution/__init__.py +63 -0
- pyoq/query/execution/aio/__init__.py +31 -0
- pyoq/query/execution/aio/operations.py +228 -0
- pyoq/query/execution/aio/pooling.py +233 -0
- pyoq/query/execution/aio/streaming.py +161 -0
- pyoq/query/execution/aio/transactions.py +105 -0
- pyoq/query/execution/batch.py +96 -0
- pyoq/query/execution/binding_style.py +30 -0
- pyoq/query/execution/compilation.py +48 -0
- pyoq/query/execution/context.py +61 -0
- pyoq/query/execution/control.py +50 -0
- pyoq/query/execution/operations.py +224 -0
- pyoq/query/execution/planning.py +107 -0
- pyoq/query/execution/pooling.py +279 -0
- pyoq/query/execution/results.py +36 -0
- pyoq/query/execution/streaming.py +178 -0
- pyoq/query/execution/transactions.py +95 -0
- pyoq/query/expressions.py +1200 -0
- pyoq/query/fields.py +60 -0
- pyoq/query/mysql/__init__.py +59 -0
- pyoq/query/mysql/aio/__init__.py +38 -0
- pyoq/query/mysql/aio/commands.py +389 -0
- pyoq/query/mysql/aio/driver.py +196 -0
- pyoq/query/mysql/aio/executor.py +123 -0
- pyoq/query/mysql/aio/factory.py +26 -0
- pyoq/query/mysql/aio/operations.py +38 -0
- pyoq/query/mysql/aio/pool.py +53 -0
- pyoq/query/mysql/aio/transactions.py +313 -0
- pyoq/query/mysql/commands.py +354 -0
- pyoq/query/mysql/compiler.py +134 -0
- pyoq/query/mysql/context.py +20 -0
- pyoq/query/mysql/executor.py +126 -0
- pyoq/query/mysql/expressions.py +244 -0
- pyoq/query/mysql/factory.py +46 -0
- pyoq/query/mysql/health.py +66 -0
- pyoq/query/mysql/identifiers.py +9 -0
- pyoq/query/mysql/model.py +79 -0
- pyoq/query/mysql/operations.py +43 -0
- pyoq/query/mysql/parameters.py +69 -0
- pyoq/query/mysql/planning.py +20 -0
- pyoq/query/mysql/pool.py +67 -0
- pyoq/query/mysql/transactions.py +331 -0
- pyoq/query/mysql/writes.py +73 -0
- pyoq/query/nodes.py +750 -0
- pyoq/query/postgres/__init__.py +48 -0
- pyoq/query/postgres/aio/__init__.py +25 -0
- pyoq/query/postgres/aio/bulk.py +56 -0
- pyoq/query/postgres/aio/commands.py +264 -0
- pyoq/query/postgres/aio/executor.py +152 -0
- pyoq/query/postgres/aio/factory.py +26 -0
- pyoq/query/postgres/aio/operations.py +26 -0
- pyoq/query/postgres/aio/pool.py +40 -0
- pyoq/query/postgres/aio/transactions.py +295 -0
- pyoq/query/postgres/bulk.py +62 -0
- pyoq/query/postgres/commands.py +238 -0
- pyoq/query/postgres/compiler.py +114 -0
- pyoq/query/postgres/context.py +20 -0
- pyoq/query/postgres/executor.py +147 -0
- pyoq/query/postgres/expressions.py +311 -0
- pyoq/query/postgres/factory.py +24 -0
- pyoq/query/postgres/health.py +24 -0
- pyoq/query/postgres/identifiers.py +9 -0
- pyoq/query/postgres/model.py +81 -0
- pyoq/query/postgres/operations.py +25 -0
- pyoq/query/postgres/parameters.py +71 -0
- pyoq/query/postgres/planning.py +20 -0
- pyoq/query/postgres/pool.py +52 -0
- pyoq/query/postgres/transactions.py +295 -0
- pyoq/query/postgres/writes.py +37 -0
- pyoq/query/projections.py +105 -0
- pyoq/query/raw.py +90 -0
- pyoq/query/recursion.py +265 -0
- pyoq/query/rendering/__init__.py +1 -0
- pyoq/query/rendering/expressions.py +913 -0
- pyoq/query/rendering/identifiers.py +40 -0
- pyoq/query/rendering/projections.py +63 -0
- pyoq/query/rendering/queries.py +334 -0
- pyoq/query/rendering/sources.py +66 -0
- pyoq/query/rendering/writes.py +176 -0
- pyoq/query/results.py +459 -0
- pyoq/query/routines.py +196 -0
- pyoq/query/rows.py +156 -0
- pyoq/query/select.py +793 -0
- pyoq/query/select_nodes.py +277 -0
- pyoq/query/sources.py +236 -0
- pyoq/query/sqlite/__init__.py +43 -0
- pyoq/query/sqlite/commands.py +201 -0
- pyoq/query/sqlite/compiler.py +139 -0
- pyoq/query/sqlite/context.py +20 -0
- pyoq/query/sqlite/executor.py +119 -0
- pyoq/query/sqlite/expressions.py +224 -0
- pyoq/query/sqlite/factory.py +32 -0
- pyoq/query/sqlite/health.py +28 -0
- pyoq/query/sqlite/identifiers.py +9 -0
- pyoq/query/sqlite/model.py +73 -0
- pyoq/query/sqlite/operations.py +36 -0
- pyoq/query/sqlite/parameters.py +50 -0
- pyoq/query/sqlite/planning.py +20 -0
- pyoq/query/sqlite/pool.py +50 -0
- pyoq/query/sqlite/streaming.py +13 -0
- pyoq/query/sqlite/transactions.py +274 -0
- pyoq/query/sqlite/writes.py +35 -0
- pyoq/query/statements.py +27 -0
- pyoq/query/values.py +23 -0
- pyoq/query/vendor.py +162 -0
- pyoq/query/windows.py +424 -0
- pyoq/query/write_nodes.py +174 -0
- pyoq/query/writes.py +628 -0
- pyoq/relations/__init__.py +66 -0
- pyoq/relations/batching.py +219 -0
- pyoq/relations/derivation.py +111 -0
- pyoq/relations/fetching.py +355 -0
- pyoq/relations/graph.py +245 -0
- pyoq/relations/loading.py +74 -0
- pyoq/relations/model.py +75 -0
- pyoq/relations/planning.py +206 -0
- pyoq/runtime/__init__.py +9 -0
- pyoq/runtime/kernels.py +25 -0
- pyoq/runtime/python.py +43 -0
- pyoq/runtime/selection.py +73 -0
- pyoq/sanic/__init__.py +32 -0
- pyoq/sanic/scope.py +197 -0
- pyoq/sanic/workers.py +129 -0
- pyoq/schema/__init__.py +108 -0
- pyoq/schema/codec.py +711 -0
- pyoq/schema/models.py +604 -0
- pyoq/schema/mysql/__init__.py +16 -0
- pyoq/schema/mysql/connection.py +73 -0
- pyoq/schema/mysql/dsn.py +72 -0
- pyoq/schema/mysql/records.py +354 -0
- pyoq/schema/mysql/reflection.py +309 -0
- pyoq/schema/mysql/source.py +30 -0
- pyoq/schema/mysql/sql.py +128 -0
- pyoq/schema/mysql/types.py +105 -0
- pyoq/schema/postgres/__init__.py +13 -0
- pyoq/schema/postgres/connection.py +63 -0
- pyoq/schema/postgres/records.py +384 -0
- pyoq/schema/postgres/reflection.py +466 -0
- pyoq/schema/postgres/source.py +30 -0
- pyoq/schema/postgres/sql.py +246 -0
- pyoq/schema/postgres/types.py +98 -0
- pyoq/schema/registry.py +45 -0
- pyoq/schema/source.py +15 -0
- pyoq/schema/sqlite/__init__.py +6 -0
- pyoq/schema/sqlite/connection.py +54 -0
- pyoq/schema/sqlite/records.py +167 -0
- pyoq/schema/sqlite/reflection.py +393 -0
- pyoq/schema/sqlite/source.py +30 -0
- pyoq/schema/sqlite/sql.py +254 -0
- pyoq/schema/sqlite/types.py +74 -0
- pyoq/serving/__init__.py +23 -0
- pyoq/serving/databases.py +107 -0
- pyoq/serving/opening.py +331 -0
- pyoq/snapshots/__init__.py +20 -0
- pyoq/snapshots/drift.py +312 -0
- pyoq/snapshots/files.py +96 -0
- pyoq/snapshots/routing.py +40 -0
- pyoq/snapshots/source.py +33 -0
- pyoq/tracing/__init__.py +5 -0
- pyoq/tracing/spans.py +89 -0
- pyoq/unset.py +14 -0
- pyoq_sql-1.0.2.dist-info/METADATA +3050 -0
- pyoq_sql-1.0.2.dist-info/RECORD +267 -0
- pyoq_sql-1.0.2.dist-info/WHEEL +4 -0
- pyoq_sql-1.0.2.dist-info/entry_points.txt +3 -0
- pyoq_sql-1.0.2.dist-info/licenses/LICENSE +373 -0
pyoq/dsl/aio/queries.py
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
"""The asynchronous counterpart of a query bound to its database.
|
|
2
|
+
|
|
3
|
+
Only the ending differs. A chain is built the same way and describes the same
|
|
4
|
+
statement; the fetch at the end is awaited because the database is.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
from typing import TYPE_CHECKING, Generic, TypeVar
|
|
11
|
+
|
|
12
|
+
from pyoq.dsl.labels import labels_of
|
|
13
|
+
from pyoq.dsl.result import Result, Row
|
|
14
|
+
from pyoq.query.select import JoinStep, Query, SelectQuery, SemiJoinStep
|
|
15
|
+
from pyoq.query.select_nodes import SelectNode, SetNode
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from pyoq.descriptors import RelationshipDescriptor
|
|
19
|
+
from pyoq.query.execution.aio import AsyncQueryOperations
|
|
20
|
+
from pyoq.query.expressions import Expression
|
|
21
|
+
from pyoq.query.sources import CommonTable, SourceBase, TableLike
|
|
22
|
+
from pyoq.query.writes import ColumnReference
|
|
23
|
+
|
|
24
|
+
ResultRow = TypeVar("ResultRow", bound=tuple[object, ...])
|
|
25
|
+
Mapped = TypeVar("Mapped")
|
|
26
|
+
ScalarValue = TypeVar("ScalarValue")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AsyncBoundQuery(Generic[ResultRow]):
|
|
30
|
+
"""A query and the database it will run against."""
|
|
31
|
+
|
|
32
|
+
__slots__ = ("_operations", "_query")
|
|
33
|
+
_operations: AsyncQueryOperations
|
|
34
|
+
_query: Query[ResultRow]
|
|
35
|
+
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
operations: AsyncQueryOperations,
|
|
39
|
+
query: Query[ResultRow],
|
|
40
|
+
) -> None:
|
|
41
|
+
object.__setattr__(self, "_operations", operations)
|
|
42
|
+
object.__setattr__(self, "_query", query)
|
|
43
|
+
|
|
44
|
+
def __setattr__(self, name: str, value: object) -> None:
|
|
45
|
+
message = f"{type(self).__name__} is immutable"
|
|
46
|
+
raise AttributeError(message, name, value)
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def query(self) -> Query[ResultRow]:
|
|
50
|
+
"""The query on its own, which cannot reach a database."""
|
|
51
|
+
return self._query
|
|
52
|
+
|
|
53
|
+
def order_by(self, *terms: object) -> AsyncBoundQuery[ResultRow]:
|
|
54
|
+
return self._with(self._query.order_by(*terms))
|
|
55
|
+
|
|
56
|
+
def limit(self, value: int, /) -> AsyncBoundQuery[ResultRow]:
|
|
57
|
+
return self._with(self._query.limit(value))
|
|
58
|
+
|
|
59
|
+
def offset(self, value: int, /) -> AsyncBoundQuery[ResultRow]:
|
|
60
|
+
return self._with(self._query.offset(value))
|
|
61
|
+
|
|
62
|
+
def union(self, other: Query[ResultRow], /) -> AsyncBoundQuery[ResultRow]:
|
|
63
|
+
return self._with(self._query.union(other))
|
|
64
|
+
|
|
65
|
+
def union_all(self, other: Query[ResultRow], /) -> AsyncBoundQuery[ResultRow]:
|
|
66
|
+
return self._with(self._query.union_all(other))
|
|
67
|
+
|
|
68
|
+
def intersect(self, other: Query[ResultRow], /) -> AsyncBoundQuery[ResultRow]:
|
|
69
|
+
return self._with(self._query.intersect(other))
|
|
70
|
+
|
|
71
|
+
def except_(self, other: Query[ResultRow], /) -> AsyncBoundQuery[ResultRow]:
|
|
72
|
+
return self._with(self._query.except_(other))
|
|
73
|
+
|
|
74
|
+
async def fetch_all(self) -> Result[ResultRow]:
|
|
75
|
+
rows = tuple(await self._operations.many(self._query))
|
|
76
|
+
return Result(rows, _labels(self._query))
|
|
77
|
+
|
|
78
|
+
async def fetch_one(self) -> Row[ResultRow]:
|
|
79
|
+
"""Exactly one row, because that is what the caller said to expect."""
|
|
80
|
+
return Row(await self._operations.one(self._query), _labels(self._query))
|
|
81
|
+
|
|
82
|
+
async def fetch_optional(self) -> Row[ResultRow] | None:
|
|
83
|
+
row = await self._operations.one_or_none(self._query)
|
|
84
|
+
return None if row is None else Row(row, _labels(self._query))
|
|
85
|
+
|
|
86
|
+
async def fetch_optional_into(
|
|
87
|
+
self,
|
|
88
|
+
factory: Callable[..., Mapped],
|
|
89
|
+
/,
|
|
90
|
+
) -> Mapped | None:
|
|
91
|
+
"""One row built by the caller's own type, or nothing.
|
|
92
|
+
|
|
93
|
+
The row and the many-row result both take a factory inline.
|
|
94
|
+
A row that may be missing had to be tested for first, which
|
|
95
|
+
is the one shape that could not be asked for in the chain.
|
|
96
|
+
"""
|
|
97
|
+
row = await self.fetch_optional()
|
|
98
|
+
return None if row is None else row.into(factory)
|
|
99
|
+
|
|
100
|
+
async def fetch_value(
|
|
101
|
+
self: AsyncBoundQuery[tuple[ScalarValue]],
|
|
102
|
+
/,
|
|
103
|
+
) -> ScalarValue:
|
|
104
|
+
"""The single column of the single row.
|
|
105
|
+
|
|
106
|
+
Only a query that selected one column can answer this, which is why the
|
|
107
|
+
annotation says so rather than a check at run time.
|
|
108
|
+
"""
|
|
109
|
+
return await self._operations.scalar(self._query)
|
|
110
|
+
|
|
111
|
+
def _with(self, query: Query[ResultRow]) -> AsyncBoundQuery[ResultRow]:
|
|
112
|
+
return AsyncBoundQuery(self._operations, query)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class AsyncBoundSelect(AsyncBoundQuery[ResultRow], Generic[ResultRow]):
|
|
116
|
+
"""A SELECT that knows its database, with the builder's own shape kept."""
|
|
117
|
+
|
|
118
|
+
__slots__ = ()
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def query(self) -> SelectQuery[ResultRow]:
|
|
122
|
+
return _as_select(self._query)
|
|
123
|
+
|
|
124
|
+
def distinct(self, enabled: bool = True, /) -> AsyncBoundSelect[ResultRow]:
|
|
125
|
+
return self._select(self.query.distinct(enabled))
|
|
126
|
+
|
|
127
|
+
def from_(
|
|
128
|
+
self,
|
|
129
|
+
source: SourceBase | TableLike,
|
|
130
|
+
/,
|
|
131
|
+
) -> AsyncBoundSelect[ResultRow]:
|
|
132
|
+
return self._select(self.query.from_(source))
|
|
133
|
+
|
|
134
|
+
def join(self, source: SourceBase | TableLike, /) -> AsyncBoundJoinStep[ResultRow]:
|
|
135
|
+
"""An inner join, qualified by the clause that follows it."""
|
|
136
|
+
return AsyncBoundJoinStep(self._select, self.query.join(source))
|
|
137
|
+
|
|
138
|
+
def inner_join(
|
|
139
|
+
self,
|
|
140
|
+
source: SourceBase | TableLike,
|
|
141
|
+
/,
|
|
142
|
+
) -> AsyncBoundJoinStep[ResultRow]:
|
|
143
|
+
return AsyncBoundJoinStep(self._select, self.query.inner_join(source))
|
|
144
|
+
|
|
145
|
+
def left_join(
|
|
146
|
+
self,
|
|
147
|
+
source: SourceBase | TableLike,
|
|
148
|
+
/,
|
|
149
|
+
) -> AsyncBoundJoinStep[ResultRow]:
|
|
150
|
+
return AsyncBoundJoinStep(self._select, self.query.left_join(source))
|
|
151
|
+
|
|
152
|
+
def right_join(
|
|
153
|
+
self,
|
|
154
|
+
source: SourceBase | TableLike,
|
|
155
|
+
/,
|
|
156
|
+
) -> AsyncBoundJoinStep[ResultRow]:
|
|
157
|
+
return AsyncBoundJoinStep(self._select, self.query.right_join(source))
|
|
158
|
+
|
|
159
|
+
def full_join(
|
|
160
|
+
self,
|
|
161
|
+
source: SourceBase | TableLike,
|
|
162
|
+
/,
|
|
163
|
+
) -> AsyncBoundJoinStep[ResultRow]:
|
|
164
|
+
return AsyncBoundJoinStep(self._select, self.query.full_join(source))
|
|
165
|
+
|
|
166
|
+
def semi_join(
|
|
167
|
+
self,
|
|
168
|
+
source: SourceBase | TableLike,
|
|
169
|
+
/,
|
|
170
|
+
) -> AsyncBoundSemiJoinStep[ResultRow]:
|
|
171
|
+
"""Rows that have a match, without bringing the match back."""
|
|
172
|
+
return AsyncBoundSemiJoinStep(self._select, self.query.semi_join(source))
|
|
173
|
+
|
|
174
|
+
def anti_join(
|
|
175
|
+
self,
|
|
176
|
+
source: SourceBase | TableLike,
|
|
177
|
+
/,
|
|
178
|
+
) -> AsyncBoundSemiJoinStep[ResultRow]:
|
|
179
|
+
"""Rows that have no match."""
|
|
180
|
+
return AsyncBoundSemiJoinStep(self._select, self.query.anti_join(source))
|
|
181
|
+
|
|
182
|
+
def cross_join(
|
|
183
|
+
self,
|
|
184
|
+
source: SourceBase | TableLike,
|
|
185
|
+
/,
|
|
186
|
+
) -> AsyncBoundSelect[ResultRow]:
|
|
187
|
+
return self._select(self.query.cross_join(source))
|
|
188
|
+
|
|
189
|
+
def natural_join(
|
|
190
|
+
self,
|
|
191
|
+
source: SourceBase | TableLike,
|
|
192
|
+
/,
|
|
193
|
+
) -> AsyncBoundSelect[ResultRow]:
|
|
194
|
+
return self._select(self.query.natural_join(source))
|
|
195
|
+
|
|
196
|
+
def natural_left_join(
|
|
197
|
+
self,
|
|
198
|
+
source: SourceBase | TableLike,
|
|
199
|
+
/,
|
|
200
|
+
) -> AsyncBoundSelect[ResultRow]:
|
|
201
|
+
return self._select(self.query.natural_left_join(source))
|
|
202
|
+
|
|
203
|
+
def natural_right_join(
|
|
204
|
+
self,
|
|
205
|
+
source: SourceBase | TableLike,
|
|
206
|
+
/,
|
|
207
|
+
) -> AsyncBoundSelect[ResultRow]:
|
|
208
|
+
return self._select(self.query.natural_right_join(source))
|
|
209
|
+
|
|
210
|
+
def natural_full_join(
|
|
211
|
+
self,
|
|
212
|
+
source: SourceBase | TableLike,
|
|
213
|
+
/,
|
|
214
|
+
) -> AsyncBoundSelect[ResultRow]:
|
|
215
|
+
return self._select(self.query.natural_full_join(source))
|
|
216
|
+
|
|
217
|
+
def where(
|
|
218
|
+
self,
|
|
219
|
+
condition: Expression[bool],
|
|
220
|
+
/,
|
|
221
|
+
) -> AsyncBoundSelect[ResultRow]:
|
|
222
|
+
return self._select(self.query.where(condition))
|
|
223
|
+
|
|
224
|
+
def group_by(self, *expressions: object) -> AsyncBoundSelect[ResultRow]:
|
|
225
|
+
return self._select(self.query.group_by(*expressions))
|
|
226
|
+
|
|
227
|
+
def having(
|
|
228
|
+
self,
|
|
229
|
+
condition: Expression[bool],
|
|
230
|
+
/,
|
|
231
|
+
) -> AsyncBoundSelect[ResultRow]:
|
|
232
|
+
return self._select(self.query.having(condition))
|
|
233
|
+
|
|
234
|
+
def with_(
|
|
235
|
+
self,
|
|
236
|
+
*common_tables: CommonTable[object],
|
|
237
|
+
) -> AsyncBoundSelect[ResultRow]:
|
|
238
|
+
return self._select(self.query.with_(*common_tables))
|
|
239
|
+
|
|
240
|
+
def order_by(self, *terms: object) -> AsyncBoundSelect[ResultRow]:
|
|
241
|
+
return self._select(self.query.order_by(*terms))
|
|
242
|
+
|
|
243
|
+
def limit(self, value: int, /) -> AsyncBoundSelect[ResultRow]:
|
|
244
|
+
return self._select(self.query.limit(value))
|
|
245
|
+
|
|
246
|
+
def offset(self, value: int, /) -> AsyncBoundSelect[ResultRow]:
|
|
247
|
+
return self._select(self.query.offset(value))
|
|
248
|
+
|
|
249
|
+
def _select(
|
|
250
|
+
self,
|
|
251
|
+
query: SelectQuery[ResultRow],
|
|
252
|
+
) -> AsyncBoundSelect[ResultRow]:
|
|
253
|
+
return AsyncBoundSelect(self._operations, query)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def _as_select(query: Query[ResultRow]) -> SelectQuery[ResultRow]:
|
|
257
|
+
if not isinstance(query, SelectQuery):
|
|
258
|
+
message = "the query is no longer a SELECT"
|
|
259
|
+
raise TypeError(message)
|
|
260
|
+
return query
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def _labels(query: Query[ResultRow]) -> tuple[str | None, ...]:
|
|
264
|
+
"""A set operation takes its names from the first query in it."""
|
|
265
|
+
select = _first_select(query.node)
|
|
266
|
+
return () if select is None else labels_of(select.projections)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _first_select(node: object) -> SelectNode | None:
|
|
270
|
+
while isinstance(node, SetNode):
|
|
271
|
+
node = node.left
|
|
272
|
+
return node if isinstance(node, SelectNode) else None
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class AsyncBoundJoinStep(Generic[ResultRow]):
|
|
276
|
+
"""A bound join waiting to be told how the two tables line up."""
|
|
277
|
+
|
|
278
|
+
__slots__ = ("_bind", "_step")
|
|
279
|
+
_bind: Callable[[SelectQuery[ResultRow]], AsyncBoundSelect[ResultRow]]
|
|
280
|
+
_step: JoinStep[ResultRow]
|
|
281
|
+
|
|
282
|
+
def __init__(
|
|
283
|
+
self,
|
|
284
|
+
bind: Callable[[SelectQuery[ResultRow]], AsyncBoundSelect[ResultRow]],
|
|
285
|
+
step: JoinStep[ResultRow],
|
|
286
|
+
) -> None:
|
|
287
|
+
object.__setattr__(self, "_bind", bind)
|
|
288
|
+
object.__setattr__(self, "_step", step)
|
|
289
|
+
|
|
290
|
+
def __setattr__(self, name: str, value: object) -> None:
|
|
291
|
+
message = "join steps are immutable"
|
|
292
|
+
raise AttributeError(message, name, value)
|
|
293
|
+
|
|
294
|
+
def on(self, condition: Expression[bool], /) -> AsyncBoundSelect[ResultRow]:
|
|
295
|
+
"""The predicate the rows are matched by."""
|
|
296
|
+
return self._bind(self._step.on(condition))
|
|
297
|
+
|
|
298
|
+
def using(self, *columns: str | ColumnReference) -> AsyncBoundSelect[ResultRow]:
|
|
299
|
+
"""Matched on columns both tables name the same way."""
|
|
300
|
+
return self._bind(self._step.using(*columns))
|
|
301
|
+
|
|
302
|
+
def on_key(
|
|
303
|
+
self,
|
|
304
|
+
relation: RelationshipDescriptor[object, object],
|
|
305
|
+
/,
|
|
306
|
+
) -> AsyncBoundSelect[ResultRow]:
|
|
307
|
+
"""Matched on the foreign key the schema already declares."""
|
|
308
|
+
return self._bind(self._step.on_key(relation))
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
class AsyncBoundSemiJoinStep(Generic[ResultRow]):
|
|
312
|
+
"""A bound semi or anti join waiting for its predicate."""
|
|
313
|
+
|
|
314
|
+
__slots__ = ("_bind", "_step")
|
|
315
|
+
_bind: Callable[[SelectQuery[ResultRow]], AsyncBoundSelect[ResultRow]]
|
|
316
|
+
_step: SemiJoinStep[ResultRow]
|
|
317
|
+
|
|
318
|
+
def __init__(
|
|
319
|
+
self,
|
|
320
|
+
bind: Callable[[SelectQuery[ResultRow]], AsyncBoundSelect[ResultRow]],
|
|
321
|
+
step: SemiJoinStep[ResultRow],
|
|
322
|
+
) -> None:
|
|
323
|
+
object.__setattr__(self, "_bind", bind)
|
|
324
|
+
object.__setattr__(self, "_step", step)
|
|
325
|
+
|
|
326
|
+
def __setattr__(self, name: str, value: object) -> None:
|
|
327
|
+
message = "join steps are immutable"
|
|
328
|
+
raise AttributeError(message, name, value)
|
|
329
|
+
|
|
330
|
+
def on(self, condition: Expression[bool], /) -> AsyncBoundSelect[ResultRow]:
|
|
331
|
+
"""The predicate a row is matched by."""
|
|
332
|
+
return self._bind(self._step.on(condition))
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
__all__ = ("AsyncBoundQuery", "AsyncBoundSelect")
|
pyoq/dsl/aio/writes.py
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
"""The asynchronous counterpart of a write bound to its database."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Generic, TypeVar, TypeVarTuple, cast, overload
|
|
6
|
+
|
|
7
|
+
from pyoq.dsl.labels import labels_of
|
|
8
|
+
from pyoq.dsl.result import Result, Row
|
|
9
|
+
from pyoq.query.write_nodes import WriteNode
|
|
10
|
+
from pyoq.query.writes import (
|
|
11
|
+
ConflictUpdate,
|
|
12
|
+
DeleteStatement,
|
|
13
|
+
InsertStatement,
|
|
14
|
+
MutationStatement,
|
|
15
|
+
ReturningStatement,
|
|
16
|
+
UpdateStatement,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from collections.abc import Callable, Iterable
|
|
21
|
+
|
|
22
|
+
from pyoq.query.execution.aio import AsyncQueryOperations
|
|
23
|
+
from pyoq.query.expressions import Expression
|
|
24
|
+
from pyoq.query.writes import ColumnReference
|
|
25
|
+
|
|
26
|
+
Values = TypeVarTuple("Values")
|
|
27
|
+
Mutation = TypeVar("Mutation", bound=MutationStatement[WriteNode])
|
|
28
|
+
ResultRow = TypeVar("ResultRow", bound=tuple[object, ...])
|
|
29
|
+
Mapped = TypeVar("Mapped")
|
|
30
|
+
ScalarValue = TypeVar("ScalarValue")
|
|
31
|
+
Value1 = TypeVar("Value1")
|
|
32
|
+
Value2 = TypeVar("Value2")
|
|
33
|
+
Value3 = TypeVar("Value3")
|
|
34
|
+
Value4 = TypeVar("Value4")
|
|
35
|
+
Value5 = TypeVar("Value5")
|
|
36
|
+
Value6 = TypeVar("Value6")
|
|
37
|
+
Value7 = TypeVar("Value7")
|
|
38
|
+
Value8 = TypeVar("Value8")
|
|
39
|
+
AssignedValue = TypeVar("AssignedValue")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class AsyncBoundReturning(Generic[ResultRow]):
|
|
43
|
+
"""Rows a write handed back, read the way a query's rows are read."""
|
|
44
|
+
|
|
45
|
+
__slots__ = ("_operations", "_statement")
|
|
46
|
+
_operations: AsyncQueryOperations
|
|
47
|
+
_statement: ReturningStatement[ResultRow]
|
|
48
|
+
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
operations: AsyncQueryOperations,
|
|
52
|
+
statement: ReturningStatement[ResultRow],
|
|
53
|
+
) -> None:
|
|
54
|
+
object.__setattr__(self, "_operations", operations)
|
|
55
|
+
object.__setattr__(self, "_statement", statement)
|
|
56
|
+
|
|
57
|
+
def __setattr__(self, name: str, value: object) -> None:
|
|
58
|
+
message = f"{type(self).__name__} is immutable"
|
|
59
|
+
raise AttributeError(message, name, value)
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def statement(self) -> ReturningStatement[ResultRow]:
|
|
63
|
+
return self._statement
|
|
64
|
+
|
|
65
|
+
async def fetch_all(self) -> Result[ResultRow]:
|
|
66
|
+
rows = tuple(await self._operations.many(self._statement))
|
|
67
|
+
return Result(rows, labels_of(self._statement.node.returning))
|
|
68
|
+
|
|
69
|
+
async def fetch_one(self) -> Row[ResultRow]:
|
|
70
|
+
"""Exactly one row, because that is what the caller said to expect."""
|
|
71
|
+
return Row(
|
|
72
|
+
await self._operations.one(self._statement),
|
|
73
|
+
labels_of(self._statement.node.returning),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
async def fetch_optional(self) -> Row[ResultRow] | None:
|
|
77
|
+
row = await self._operations.one_or_none(self._statement)
|
|
78
|
+
return (
|
|
79
|
+
None if row is None else Row(row, labels_of(self._statement.node.returning))
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
async def fetch_optional_into(
|
|
83
|
+
self,
|
|
84
|
+
factory: Callable[..., Mapped],
|
|
85
|
+
/,
|
|
86
|
+
) -> Mapped | None:
|
|
87
|
+
"""One row built by the caller's own type, or nothing.
|
|
88
|
+
|
|
89
|
+
The row and the many-row result both take a factory inline.
|
|
90
|
+
A row that may be missing had to be tested for first, which
|
|
91
|
+
is the one shape that could not be asked for in the chain.
|
|
92
|
+
"""
|
|
93
|
+
row = await self.fetch_optional()
|
|
94
|
+
return None if row is None else row.into(factory)
|
|
95
|
+
|
|
96
|
+
async def fetch_value(
|
|
97
|
+
self: AsyncBoundReturning[tuple[ScalarValue]],
|
|
98
|
+
/,
|
|
99
|
+
) -> ScalarValue:
|
|
100
|
+
return await self._operations.scalar(self._statement)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class AsyncBoundMutation(Generic[Mutation]):
|
|
104
|
+
"""What every bound write can do, whatever it is writing."""
|
|
105
|
+
|
|
106
|
+
__slots__ = ("_operations", "_statement")
|
|
107
|
+
_operations: AsyncQueryOperations
|
|
108
|
+
_statement: Mutation
|
|
109
|
+
|
|
110
|
+
def __init__(
|
|
111
|
+
self,
|
|
112
|
+
operations: AsyncQueryOperations,
|
|
113
|
+
statement: Mutation,
|
|
114
|
+
) -> None:
|
|
115
|
+
object.__setattr__(self, "_operations", operations)
|
|
116
|
+
object.__setattr__(self, "_statement", statement)
|
|
117
|
+
|
|
118
|
+
def __setattr__(self, name: str, value: object) -> None:
|
|
119
|
+
message = f"{type(self).__name__} is immutable"
|
|
120
|
+
raise AttributeError(message, name, value)
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
def statement(self) -> Mutation:
|
|
124
|
+
"""The statement on its own, which cannot reach a database."""
|
|
125
|
+
return self._statement
|
|
126
|
+
|
|
127
|
+
async def execute(self) -> int:
|
|
128
|
+
"""How many rows the database says it wrote."""
|
|
129
|
+
written = await self._operations.execute(self._statement)
|
|
130
|
+
return written.rows_affected
|
|
131
|
+
|
|
132
|
+
def returning_all(self) -> AsyncBoundReturning[tuple[object, ...]]:
|
|
133
|
+
"""Every column the table declares, without listing them."""
|
|
134
|
+
return AsyncBoundReturning(self._operations, self._statement.returning_all())
|
|
135
|
+
|
|
136
|
+
@overload
|
|
137
|
+
def returning(
|
|
138
|
+
self,
|
|
139
|
+
value1: Expression[Value1],
|
|
140
|
+
/,
|
|
141
|
+
) -> AsyncBoundReturning[tuple[Value1]]: ...
|
|
142
|
+
|
|
143
|
+
@overload
|
|
144
|
+
def returning(
|
|
145
|
+
self,
|
|
146
|
+
value1: Expression[Value1],
|
|
147
|
+
value2: Expression[Value2],
|
|
148
|
+
/,
|
|
149
|
+
) -> AsyncBoundReturning[tuple[Value1, Value2]]: ...
|
|
150
|
+
|
|
151
|
+
@overload
|
|
152
|
+
def returning(
|
|
153
|
+
self,
|
|
154
|
+
value1: Expression[Value1],
|
|
155
|
+
value2: Expression[Value2],
|
|
156
|
+
value3: Expression[Value3],
|
|
157
|
+
/,
|
|
158
|
+
) -> AsyncBoundReturning[tuple[Value1, Value2, Value3]]: ...
|
|
159
|
+
|
|
160
|
+
@overload
|
|
161
|
+
def returning(
|
|
162
|
+
self,
|
|
163
|
+
value1: Expression[Value1],
|
|
164
|
+
value2: Expression[Value2],
|
|
165
|
+
value3: Expression[Value3],
|
|
166
|
+
value4: Expression[Value4],
|
|
167
|
+
/,
|
|
168
|
+
) -> AsyncBoundReturning[tuple[Value1, Value2, Value3, Value4]]: ...
|
|
169
|
+
|
|
170
|
+
@overload
|
|
171
|
+
def returning(
|
|
172
|
+
self,
|
|
173
|
+
value1: Expression[Value1],
|
|
174
|
+
value2: Expression[Value2],
|
|
175
|
+
value3: Expression[Value3],
|
|
176
|
+
value4: Expression[Value4],
|
|
177
|
+
value5: Expression[Value5],
|
|
178
|
+
/,
|
|
179
|
+
) -> AsyncBoundReturning[tuple[Value1, Value2, Value3, Value4, Value5]]: ...
|
|
180
|
+
|
|
181
|
+
@overload
|
|
182
|
+
def returning(
|
|
183
|
+
self,
|
|
184
|
+
value1: Expression[Value1],
|
|
185
|
+
value2: Expression[Value2],
|
|
186
|
+
value3: Expression[Value3],
|
|
187
|
+
value4: Expression[Value4],
|
|
188
|
+
value5: Expression[Value5],
|
|
189
|
+
value6: Expression[Value6],
|
|
190
|
+
/,
|
|
191
|
+
) -> AsyncBoundReturning[tuple[Value1, Value2, Value3, Value4, Value5, Value6]]: ...
|
|
192
|
+
|
|
193
|
+
@overload
|
|
194
|
+
def returning(
|
|
195
|
+
self,
|
|
196
|
+
value1: Expression[Value1],
|
|
197
|
+
value2: Expression[Value2],
|
|
198
|
+
value3: Expression[Value3],
|
|
199
|
+
value4: Expression[Value4],
|
|
200
|
+
value5: Expression[Value5],
|
|
201
|
+
value6: Expression[Value6],
|
|
202
|
+
value7: Expression[Value7],
|
|
203
|
+
/,
|
|
204
|
+
) -> AsyncBoundReturning[
|
|
205
|
+
tuple[Value1, Value2, Value3, Value4, Value5, Value6, Value7]
|
|
206
|
+
]: ...
|
|
207
|
+
|
|
208
|
+
@overload
|
|
209
|
+
def returning(
|
|
210
|
+
self,
|
|
211
|
+
value1: Expression[Value1],
|
|
212
|
+
value2: Expression[Value2],
|
|
213
|
+
value3: Expression[Value3],
|
|
214
|
+
value4: Expression[Value4],
|
|
215
|
+
value5: Expression[Value5],
|
|
216
|
+
value6: Expression[Value6],
|
|
217
|
+
value7: Expression[Value7],
|
|
218
|
+
value8: Expression[Value8],
|
|
219
|
+
/,
|
|
220
|
+
) -> AsyncBoundReturning[
|
|
221
|
+
tuple[Value1, Value2, Value3, Value4, Value5, Value6, Value7, Value8]
|
|
222
|
+
]: ...
|
|
223
|
+
|
|
224
|
+
@overload
|
|
225
|
+
def returning(
|
|
226
|
+
self,
|
|
227
|
+
value1: object,
|
|
228
|
+
value2: object,
|
|
229
|
+
value3: object,
|
|
230
|
+
value4: object,
|
|
231
|
+
value5: object,
|
|
232
|
+
value6: object,
|
|
233
|
+
value7: object,
|
|
234
|
+
value8: object,
|
|
235
|
+
/,
|
|
236
|
+
*values: object,
|
|
237
|
+
) -> AsyncBoundReturning[tuple[object, ...]]:
|
|
238
|
+
"""Wider than the overloads above name, where the types stop.
|
|
239
|
+
|
|
240
|
+
A statement is still a statement past eight returned columns,
|
|
241
|
+
and matching no overload would take the whole chain down with
|
|
242
|
+
it rather than just the tuple.
|
|
243
|
+
"""
|
|
244
|
+
|
|
245
|
+
def returning( # type: ignore[misc]
|
|
246
|
+
self,
|
|
247
|
+
*values: object,
|
|
248
|
+
) -> AsyncBoundReturning[tuple[object, ...]]:
|
|
249
|
+
# The builder declares typed overloads for callers; this is the one
|
|
250
|
+
# implementation behind them, reached variadically.
|
|
251
|
+
build = cast(
|
|
252
|
+
"Callable[..., ReturningStatement[tuple[object, ...]]]",
|
|
253
|
+
self._statement.returning,
|
|
254
|
+
)
|
|
255
|
+
return AsyncBoundReturning(self._operations, build(*values))
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class AsyncBoundInsert(
|
|
259
|
+
AsyncBoundMutation[InsertStatement[*Values]],
|
|
260
|
+
Generic[*Values],
|
|
261
|
+
):
|
|
262
|
+
"""An INSERT and the database it will run against."""
|
|
263
|
+
|
|
264
|
+
__slots__ = ()
|
|
265
|
+
|
|
266
|
+
def values(self, *values: *Values) -> AsyncBoundInsert[*Values]:
|
|
267
|
+
return AsyncBoundInsert(self._operations, self._statement.values(*values))
|
|
268
|
+
|
|
269
|
+
def values_many(self, rows: Iterable[object], /) -> AsyncBoundInsert[*Values]:
|
|
270
|
+
return AsyncBoundInsert(self._operations, self._statement.values_many(rows))
|
|
271
|
+
|
|
272
|
+
def on_conflict_do_nothing(
|
|
273
|
+
self,
|
|
274
|
+
*columns: ColumnReference,
|
|
275
|
+
) -> AsyncBoundInsert[*Values]:
|
|
276
|
+
return AsyncBoundInsert(
|
|
277
|
+
self._operations,
|
|
278
|
+
self._statement.on_conflict_do_nothing(*columns),
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
def on_conflict_do_update(
|
|
282
|
+
self,
|
|
283
|
+
*columns: ColumnReference,
|
|
284
|
+
) -> AsyncBoundConflictUpdate[*Values]:
|
|
285
|
+
return AsyncBoundConflictUpdate(
|
|
286
|
+
self._operations,
|
|
287
|
+
self._statement.on_conflict_do_update(*columns),
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
class AsyncBoundConflictUpdate(
|
|
292
|
+
AsyncBoundMutation[ConflictUpdate[*Values]],
|
|
293
|
+
Generic[*Values],
|
|
294
|
+
):
|
|
295
|
+
"""The SET and WHERE that belong to a conflict clause."""
|
|
296
|
+
|
|
297
|
+
__slots__ = ()
|
|
298
|
+
|
|
299
|
+
def set(
|
|
300
|
+
self,
|
|
301
|
+
column: Expression[AssignedValue],
|
|
302
|
+
value: AssignedValue | Expression[AssignedValue],
|
|
303
|
+
/,
|
|
304
|
+
) -> AsyncBoundConflictUpdate[*Values]:
|
|
305
|
+
return AsyncBoundConflictUpdate(
|
|
306
|
+
self._operations, self._statement.set(column, value)
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
def where(
|
|
310
|
+
self,
|
|
311
|
+
condition: Expression[bool],
|
|
312
|
+
/,
|
|
313
|
+
) -> AsyncBoundConflictUpdate[*Values]:
|
|
314
|
+
return AsyncBoundConflictUpdate(
|
|
315
|
+
self._operations, self._statement.where(condition)
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
class AsyncBoundUpdate(AsyncBoundMutation[UpdateStatement]):
|
|
320
|
+
"""An UPDATE, which has to say which rows it means."""
|
|
321
|
+
|
|
322
|
+
__slots__ = ()
|
|
323
|
+
|
|
324
|
+
def set(
|
|
325
|
+
self,
|
|
326
|
+
column: Expression[AssignedValue],
|
|
327
|
+
value: AssignedValue | Expression[AssignedValue],
|
|
328
|
+
/,
|
|
329
|
+
) -> AsyncBoundUpdate:
|
|
330
|
+
return AsyncBoundUpdate(self._operations, self._statement.set(column, value))
|
|
331
|
+
|
|
332
|
+
def set_values(
|
|
333
|
+
self,
|
|
334
|
+
values: object,
|
|
335
|
+
/,
|
|
336
|
+
*columns: ColumnReference,
|
|
337
|
+
) -> AsyncBoundUpdate:
|
|
338
|
+
return AsyncBoundUpdate(
|
|
339
|
+
self._operations, self._statement.set_values(values, *columns)
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
def where(self, condition: Expression[bool], /) -> AsyncBoundUpdate:
|
|
343
|
+
return AsyncBoundUpdate(self._operations, self._statement.where(condition))
|
|
344
|
+
|
|
345
|
+
def all_rows(self) -> AsyncBoundUpdate:
|
|
346
|
+
return AsyncBoundUpdate(self._operations, self._statement.all_rows())
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
class AsyncBoundDelete(AsyncBoundMutation[DeleteStatement]):
|
|
350
|
+
"""A DELETE, which has to say which rows it means."""
|
|
351
|
+
|
|
352
|
+
__slots__ = ()
|
|
353
|
+
|
|
354
|
+
def where(self, condition: Expression[bool], /) -> AsyncBoundDelete:
|
|
355
|
+
return AsyncBoundDelete(self._operations, self._statement.where(condition))
|
|
356
|
+
|
|
357
|
+
def all_rows(self) -> AsyncBoundDelete:
|
|
358
|
+
return AsyncBoundDelete(self._operations, self._statement.all_rows())
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
__all__ = (
|
|
362
|
+
"AsyncBoundConflictUpdate",
|
|
363
|
+
"AsyncBoundDelete",
|
|
364
|
+
"AsyncBoundInsert",
|
|
365
|
+
"AsyncBoundMutation",
|
|
366
|
+
"AsyncBoundReturning",
|
|
367
|
+
"AsyncBoundUpdate",
|
|
368
|
+
)
|