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/context.py
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
"""The entry point that ties a query to a database.
|
|
2
|
+
|
|
3
|
+
PyOQ's builders describe a statement and never reach a database, which is what
|
|
4
|
+
makes them safe to share, cache, and test. A context does not change that: it
|
|
5
|
+
holds the operations to run against and hands back builders that carry it, so a
|
|
6
|
+
chain can end in a fetch instead of being passed to an executor.
|
|
7
|
+
|
|
8
|
+
The unattached builders are still there and still cannot execute. Anything built
|
|
9
|
+
with them runs through `fetch` or `execute` here.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from typing import TYPE_CHECKING, TypeVar, TypeVarTuple, cast, overload
|
|
15
|
+
|
|
16
|
+
from pyoq.dsl.labels import labels_of
|
|
17
|
+
from pyoq.dsl.queries import BoundSelect
|
|
18
|
+
from pyoq.dsl.result import Result
|
|
19
|
+
from pyoq.dsl.writes import BoundDelete, BoundInsert, BoundUpdate
|
|
20
|
+
from pyoq.query.select import SelectQuery, select, select_from
|
|
21
|
+
from pyoq.query.select_nodes import SelectNode
|
|
22
|
+
from pyoq.query.writes import (
|
|
23
|
+
InsertStatement,
|
|
24
|
+
ReturningStatement,
|
|
25
|
+
delete_from,
|
|
26
|
+
insert_into,
|
|
27
|
+
update,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from collections.abc import Callable
|
|
32
|
+
|
|
33
|
+
from pyoq.query.execution import QueryOperations
|
|
34
|
+
from pyoq.query.expressions import Expression
|
|
35
|
+
from pyoq.query.projections import Projection
|
|
36
|
+
from pyoq.query.routines import Call
|
|
37
|
+
from pyoq.query.select import Query
|
|
38
|
+
from pyoq.query.sources import ColumnedTable, TableLike
|
|
39
|
+
|
|
40
|
+
ResultRow = TypeVar("ResultRow", bound=tuple[object, ...])
|
|
41
|
+
Values = TypeVarTuple("Values")
|
|
42
|
+
Value1 = TypeVar("Value1")
|
|
43
|
+
Value2 = TypeVar("Value2")
|
|
44
|
+
Value3 = TypeVar("Value3")
|
|
45
|
+
Value4 = TypeVar("Value4")
|
|
46
|
+
Value5 = TypeVar("Value5")
|
|
47
|
+
Value6 = TypeVar("Value6")
|
|
48
|
+
Value7 = TypeVar("Value7")
|
|
49
|
+
Value8 = TypeVar("Value8")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class DslContext:
|
|
53
|
+
"""A database to build against."""
|
|
54
|
+
|
|
55
|
+
__slots__ = ("_operations",)
|
|
56
|
+
_operations: QueryOperations
|
|
57
|
+
|
|
58
|
+
def __init__(self, operations: QueryOperations) -> None:
|
|
59
|
+
object.__setattr__(self, "_operations", operations)
|
|
60
|
+
|
|
61
|
+
def __setattr__(self, name: str, value: object) -> None:
|
|
62
|
+
message = f"{type(self).__name__} is immutable"
|
|
63
|
+
raise AttributeError(message, name, value)
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def operations(self) -> QueryOperations:
|
|
67
|
+
return self._operations
|
|
68
|
+
|
|
69
|
+
@overload
|
|
70
|
+
def select(
|
|
71
|
+
self,
|
|
72
|
+
value1: Expression[Value1] | Projection[Value1],
|
|
73
|
+
/,
|
|
74
|
+
) -> BoundSelect[tuple[Value1]]: ...
|
|
75
|
+
|
|
76
|
+
@overload
|
|
77
|
+
def select(
|
|
78
|
+
self,
|
|
79
|
+
value1: Expression[Value1] | Projection[Value1],
|
|
80
|
+
value2: Expression[Value2] | Projection[Value2],
|
|
81
|
+
/,
|
|
82
|
+
) -> BoundSelect[tuple[Value1, Value2]]: ...
|
|
83
|
+
|
|
84
|
+
@overload
|
|
85
|
+
def select(
|
|
86
|
+
self,
|
|
87
|
+
value1: Expression[Value1] | Projection[Value1],
|
|
88
|
+
value2: Expression[Value2] | Projection[Value2],
|
|
89
|
+
value3: Expression[Value3] | Projection[Value3],
|
|
90
|
+
/,
|
|
91
|
+
) -> BoundSelect[tuple[Value1, Value2, Value3]]: ...
|
|
92
|
+
|
|
93
|
+
@overload
|
|
94
|
+
def select(
|
|
95
|
+
self,
|
|
96
|
+
value1: Expression[Value1] | Projection[Value1],
|
|
97
|
+
value2: Expression[Value2] | Projection[Value2],
|
|
98
|
+
value3: Expression[Value3] | Projection[Value3],
|
|
99
|
+
value4: Expression[Value4] | Projection[Value4],
|
|
100
|
+
/,
|
|
101
|
+
) -> BoundSelect[tuple[Value1, Value2, Value3, Value4]]: ...
|
|
102
|
+
|
|
103
|
+
@overload
|
|
104
|
+
def select(
|
|
105
|
+
self,
|
|
106
|
+
value1: Expression[Value1] | Projection[Value1],
|
|
107
|
+
value2: Expression[Value2] | Projection[Value2],
|
|
108
|
+
value3: Expression[Value3] | Projection[Value3],
|
|
109
|
+
value4: Expression[Value4] | Projection[Value4],
|
|
110
|
+
value5: Expression[Value5] | Projection[Value5],
|
|
111
|
+
/,
|
|
112
|
+
) -> BoundSelect[tuple[Value1, Value2, Value3, Value4, Value5]]: ...
|
|
113
|
+
|
|
114
|
+
@overload
|
|
115
|
+
def select(
|
|
116
|
+
self,
|
|
117
|
+
value1: Expression[Value1] | Projection[Value1],
|
|
118
|
+
value2: Expression[Value2] | Projection[Value2],
|
|
119
|
+
value3: Expression[Value3] | Projection[Value3],
|
|
120
|
+
value4: Expression[Value4] | Projection[Value4],
|
|
121
|
+
value5: Expression[Value5] | Projection[Value5],
|
|
122
|
+
value6: Expression[Value6] | Projection[Value6],
|
|
123
|
+
/,
|
|
124
|
+
) -> BoundSelect[tuple[Value1, Value2, Value3, Value4, Value5, Value6]]: ...
|
|
125
|
+
|
|
126
|
+
@overload
|
|
127
|
+
def select(
|
|
128
|
+
self,
|
|
129
|
+
value1: Expression[Value1] | Projection[Value1],
|
|
130
|
+
value2: Expression[Value2] | Projection[Value2],
|
|
131
|
+
value3: Expression[Value3] | Projection[Value3],
|
|
132
|
+
value4: Expression[Value4] | Projection[Value4],
|
|
133
|
+
value5: Expression[Value5] | Projection[Value5],
|
|
134
|
+
value6: Expression[Value6] | Projection[Value6],
|
|
135
|
+
value7: Expression[Value7] | Projection[Value7],
|
|
136
|
+
/,
|
|
137
|
+
) -> BoundSelect[tuple[Value1, Value2, Value3, Value4, Value5, Value6, Value7]]: ...
|
|
138
|
+
|
|
139
|
+
@overload
|
|
140
|
+
def select(
|
|
141
|
+
self,
|
|
142
|
+
value1: Expression[Value1] | Projection[Value1],
|
|
143
|
+
value2: Expression[Value2] | Projection[Value2],
|
|
144
|
+
value3: Expression[Value3] | Projection[Value3],
|
|
145
|
+
value4: Expression[Value4] | Projection[Value4],
|
|
146
|
+
value5: Expression[Value5] | Projection[Value5],
|
|
147
|
+
value6: Expression[Value6] | Projection[Value6],
|
|
148
|
+
value7: Expression[Value7] | Projection[Value7],
|
|
149
|
+
value8: Expression[Value8] | Projection[Value8],
|
|
150
|
+
/,
|
|
151
|
+
) -> BoundSelect[
|
|
152
|
+
tuple[Value1, Value2, Value3, Value4, Value5, Value6, Value7, Value8]
|
|
153
|
+
]: ...
|
|
154
|
+
|
|
155
|
+
@overload
|
|
156
|
+
def select(
|
|
157
|
+
self,
|
|
158
|
+
value1: object,
|
|
159
|
+
value2: object,
|
|
160
|
+
value3: object,
|
|
161
|
+
value4: object,
|
|
162
|
+
value5: object,
|
|
163
|
+
value6: object,
|
|
164
|
+
value7: object,
|
|
165
|
+
value8: object,
|
|
166
|
+
/,
|
|
167
|
+
*values: object,
|
|
168
|
+
) -> BoundSelect[tuple[object, ...]]:
|
|
169
|
+
"""Wider than the overloads above name, where the element types stop.
|
|
170
|
+
|
|
171
|
+
A query is still a query past eight projections, and matching no
|
|
172
|
+
overload would take the whole chain down with it rather than just the
|
|
173
|
+
tuple. Past here a projection is checked when it is turned into one,
|
|
174
|
+
and the row is `object` per column, which is what is still known.
|
|
175
|
+
"""
|
|
176
|
+
|
|
177
|
+
def select( # type: ignore[misc]
|
|
178
|
+
self,
|
|
179
|
+
*values: object,
|
|
180
|
+
) -> BoundSelect[tuple[object, ...]]:
|
|
181
|
+
# `select` declares typed overloads for callers; this is the single
|
|
182
|
+
# implementation behind them, reached variadically. The overloads above
|
|
183
|
+
# are what a caller sees, and they carry the types across.
|
|
184
|
+
build = cast("Callable[..., SelectQuery[tuple[object, ...]]]", select)
|
|
185
|
+
return BoundSelect(self._operations, build(*values))
|
|
186
|
+
|
|
187
|
+
def select_from(self, table: ColumnedTable, /) -> BoundSelect[tuple[object, ...]]:
|
|
188
|
+
"""Every column the table declares, without naming them one by one.
|
|
189
|
+
|
|
190
|
+
The columns are written into the SQL rather than left as a star, so
|
|
191
|
+
adding one later cannot silently change what a caller reads back.
|
|
192
|
+
Values arrive in declared order, which is the order the generated row
|
|
193
|
+
type takes its arguments, so `.into(TableRow)` builds it.
|
|
194
|
+
"""
|
|
195
|
+
return BoundSelect(self._operations, select_from(table))
|
|
196
|
+
|
|
197
|
+
@overload
|
|
198
|
+
@overload
|
|
199
|
+
def insert_into(
|
|
200
|
+
self,
|
|
201
|
+
table: TableLike,
|
|
202
|
+
/,
|
|
203
|
+
column1: Expression[Value1],
|
|
204
|
+
) -> BoundInsert[Value1]: ...
|
|
205
|
+
|
|
206
|
+
@overload
|
|
207
|
+
def insert_into(
|
|
208
|
+
self,
|
|
209
|
+
table: TableLike,
|
|
210
|
+
/,
|
|
211
|
+
column1: Expression[Value1],
|
|
212
|
+
column2: Expression[Value2],
|
|
213
|
+
) -> BoundInsert[Value1, Value2]: ...
|
|
214
|
+
|
|
215
|
+
@overload
|
|
216
|
+
def insert_into(
|
|
217
|
+
self,
|
|
218
|
+
table: TableLike,
|
|
219
|
+
/,
|
|
220
|
+
column1: Expression[Value1],
|
|
221
|
+
column2: Expression[Value2],
|
|
222
|
+
column3: Expression[Value3],
|
|
223
|
+
) -> BoundInsert[Value1, Value2, Value3]: ...
|
|
224
|
+
|
|
225
|
+
@overload
|
|
226
|
+
def insert_into(
|
|
227
|
+
self,
|
|
228
|
+
table: TableLike,
|
|
229
|
+
/,
|
|
230
|
+
column1: Expression[Value1],
|
|
231
|
+
column2: Expression[Value2],
|
|
232
|
+
column3: Expression[Value3],
|
|
233
|
+
column4: Expression[Value4],
|
|
234
|
+
) -> BoundInsert[Value1, Value2, Value3, Value4]: ...
|
|
235
|
+
|
|
236
|
+
@overload
|
|
237
|
+
def insert_into(
|
|
238
|
+
self,
|
|
239
|
+
table: TableLike,
|
|
240
|
+
/,
|
|
241
|
+
column1: Expression[Value1],
|
|
242
|
+
column2: Expression[Value2],
|
|
243
|
+
column3: Expression[Value3],
|
|
244
|
+
column4: Expression[Value4],
|
|
245
|
+
column5: Expression[Value5],
|
|
246
|
+
) -> BoundInsert[Value1, Value2, Value3, Value4, Value5]: ...
|
|
247
|
+
|
|
248
|
+
@overload
|
|
249
|
+
def insert_into(
|
|
250
|
+
self,
|
|
251
|
+
table: TableLike,
|
|
252
|
+
/,
|
|
253
|
+
column1: Expression[Value1],
|
|
254
|
+
column2: Expression[Value2],
|
|
255
|
+
column3: Expression[Value3],
|
|
256
|
+
column4: Expression[Value4],
|
|
257
|
+
column5: Expression[Value5],
|
|
258
|
+
column6: Expression[Value6],
|
|
259
|
+
) -> BoundInsert[Value1, Value2, Value3, Value4, Value5, Value6]: ...
|
|
260
|
+
|
|
261
|
+
@overload
|
|
262
|
+
def insert_into(
|
|
263
|
+
self,
|
|
264
|
+
table: TableLike,
|
|
265
|
+
/,
|
|
266
|
+
column1: Expression[Value1],
|
|
267
|
+
column2: Expression[Value2],
|
|
268
|
+
column3: Expression[Value3],
|
|
269
|
+
column4: Expression[Value4],
|
|
270
|
+
column5: Expression[Value5],
|
|
271
|
+
column6: Expression[Value6],
|
|
272
|
+
column7: Expression[Value7],
|
|
273
|
+
) -> BoundInsert[Value1, Value2, Value3, Value4, Value5, Value6, Value7]: ...
|
|
274
|
+
|
|
275
|
+
@overload
|
|
276
|
+
def insert_into(
|
|
277
|
+
self,
|
|
278
|
+
table: TableLike,
|
|
279
|
+
/,
|
|
280
|
+
column1: Expression[Value1],
|
|
281
|
+
column2: Expression[Value2],
|
|
282
|
+
column3: Expression[Value3],
|
|
283
|
+
column4: Expression[Value4],
|
|
284
|
+
column5: Expression[Value5],
|
|
285
|
+
column6: Expression[Value6],
|
|
286
|
+
column7: Expression[Value7],
|
|
287
|
+
column8: Expression[Value8],
|
|
288
|
+
) -> BoundInsert[
|
|
289
|
+
Value1, Value2, Value3, Value4, Value5, Value6, Value7, Value8
|
|
290
|
+
]: ...
|
|
291
|
+
|
|
292
|
+
def insert_into( # type: ignore[misc]
|
|
293
|
+
self,
|
|
294
|
+
table: TableLike,
|
|
295
|
+
/,
|
|
296
|
+
*columns: object,
|
|
297
|
+
) -> BoundInsert[*tuple[object, ...]]:
|
|
298
|
+
build = cast("Callable[..., InsertStatement[*tuple[object, ...]]]", insert_into)
|
|
299
|
+
return BoundInsert(self._operations, build(table, *columns))
|
|
300
|
+
|
|
301
|
+
def update(self, table: TableLike, /) -> BoundUpdate:
|
|
302
|
+
return BoundUpdate(self._operations, update(table))
|
|
303
|
+
|
|
304
|
+
def delete_from(self, table: TableLike, /) -> BoundDelete:
|
|
305
|
+
return BoundDelete(self._operations, delete_from(table))
|
|
306
|
+
|
|
307
|
+
def fetch(
|
|
308
|
+
self,
|
|
309
|
+
query: Query[ResultRow] | ReturningStatement[ResultRow] | Call[ResultRow],
|
|
310
|
+
/,
|
|
311
|
+
) -> Result[ResultRow]:
|
|
312
|
+
"""Run something built the ordinary way, and read it the same way."""
|
|
313
|
+
rows = tuple(self._operations.many(query))
|
|
314
|
+
return Result(rows, _labels(query))
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def _labels(
|
|
318
|
+
query: Query[ResultRow] | ReturningStatement[ResultRow] | Call[ResultRow],
|
|
319
|
+
) -> tuple[str | None, ...]:
|
|
320
|
+
if isinstance(query, ReturningStatement):
|
|
321
|
+
return labels_of(query.node.returning)
|
|
322
|
+
node = query.node
|
|
323
|
+
return labels_of(node.projections) if isinstance(node, SelectNode) else ()
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
__all__ = ("DslContext",)
|
pyoq/dsl/entry.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Choosing a context from the database it is given.
|
|
2
|
+
|
|
3
|
+
There is one name for this because there is one question being asked. Whether
|
|
4
|
+
the fetches are awaited follows from the database, not from a second spelling.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING, overload
|
|
10
|
+
|
|
11
|
+
from pyoq.dsl.aio.context import AsyncDslContext
|
|
12
|
+
from pyoq.dsl.context import DslContext
|
|
13
|
+
from pyoq.query.execution.aio import AsyncQueryOperations
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from pyoq.query.execution import QueryOperations
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@overload
|
|
20
|
+
def using(operations: QueryOperations, /) -> DslContext: ...
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@overload
|
|
24
|
+
def using(operations: AsyncQueryOperations, /) -> AsyncDslContext: ...
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def using(
|
|
28
|
+
operations: QueryOperations | AsyncQueryOperations,
|
|
29
|
+
/,
|
|
30
|
+
) -> DslContext | AsyncDslContext:
|
|
31
|
+
"""A context over any database PyOQ can run statements against."""
|
|
32
|
+
if isinstance(operations, AsyncQueryOperations):
|
|
33
|
+
return AsyncDslContext(operations)
|
|
34
|
+
return DslContext(operations)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
__all__ = ("using",)
|
pyoq/dsl/labels.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""The name a column comes back under.
|
|
2
|
+
|
|
3
|
+
Queries and writes both project through the same node, so the rule for naming a
|
|
4
|
+
column lives here rather than once in each place that needs it.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
from pyoq.query.nodes import FieldNode
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from pyoq.query.select_nodes import ProjectionNode
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def labels_of(
|
|
18
|
+
projections: tuple[ProjectionNode, ...],
|
|
19
|
+
/,
|
|
20
|
+
) -> tuple[str | None, ...]:
|
|
21
|
+
return tuple(_label(projection) for projection in projections)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _label(projection: ProjectionNode) -> str | None:
|
|
25
|
+
"""An alias if the query gave one, otherwise the column's own name.
|
|
26
|
+
|
|
27
|
+
Anything else has no name to report, and inventing one would report a fact
|
|
28
|
+
the database never stated.
|
|
29
|
+
"""
|
|
30
|
+
if projection.alias is not None:
|
|
31
|
+
return projection.alias
|
|
32
|
+
expression = projection.expression
|
|
33
|
+
return expression.name if isinstance(expression, FieldNode) else None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
__all__ = ("labels_of",)
|