sqlakit 0.7.1__tar.gz → 0.7.3__tar.gz
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.
- {sqlakit-0.7.1 → sqlakit-0.7.3}/PKG-INFO +1 -1
- {sqlakit-0.7.1 → sqlakit-0.7.3}/pyproject.toml +1 -1
- {sqlakit-0.7.1 → sqlakit-0.7.3}/pyproject.toml.orig +1 -1
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/_query.py +35 -11
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/asyncio/orm.py +1 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/asyncio/sql.py +3 -3
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/orm.py +1 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/sql.py +3 -3
- {sqlakit-0.7.1 → sqlakit-0.7.3}/LICENSE +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/README.md +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/__init__.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/_base.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/_db.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/_discovery.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/_model.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/_recording.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/_registry.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/_routing.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/_sql.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/asyncio/__init__.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/asyncio/_db.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/asyncio/_registry.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/exceptions.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/py.typed +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/testing.py +0 -0
- {sqlakit-0.7.1 → sqlakit-0.7.3}/sqlakit/types.py +0 -0
|
@@ -466,7 +466,7 @@ class BaseQuery(Generic[ModelT]):
|
|
|
466
466
|
)
|
|
467
467
|
return query
|
|
468
468
|
|
|
469
|
-
def from_sql(self, template: str, **context: Any) -> Self: # noqa: ANN401
|
|
469
|
+
def from_sql(self, template: str, /, **context: Any) -> Self: # noqa: ANN401
|
|
470
470
|
"""Take the rows of a SQL template, mapped onto the model.
|
|
471
471
|
|
|
472
472
|
```python
|
|
@@ -587,6 +587,7 @@ class BaseQuery(Generic[ModelT]):
|
|
|
587
587
|
criteria,
|
|
588
588
|
ignore_case=ignore_case,
|
|
589
589
|
nulls=nulls,
|
|
590
|
+
model=self.model,
|
|
590
591
|
)
|
|
591
592
|
)
|
|
592
593
|
|
|
@@ -990,13 +991,14 @@ def _mapped_column(model: type[Any], name: str) -> Any: # noqa: ANN401
|
|
|
990
991
|
return column
|
|
991
992
|
|
|
992
993
|
|
|
993
|
-
def ordered(
|
|
994
|
+
def ordered( # noqa: PLR0913 - the shape of an ordering, not a call site
|
|
994
995
|
select: sa.Select[Any],
|
|
995
996
|
fields: Mapping[str, Any],
|
|
996
997
|
criteria: Iterable[Any],
|
|
997
998
|
*,
|
|
998
999
|
ignore_case: bool | Sequence[str] = False,
|
|
999
1000
|
nulls: str | None = None,
|
|
1001
|
+
model: type[Any] | None = None,
|
|
1000
1002
|
) -> sa.Select[Any]:
|
|
1001
1003
|
"""Return the statement ordered by these criteria, joining what they need.
|
|
1002
1004
|
|
|
@@ -1018,7 +1020,7 @@ def ordered(
|
|
|
1018
1020
|
clauses = []
|
|
1019
1021
|
joined: dict[str, Any] = {}
|
|
1020
1022
|
for criterion in named:
|
|
1021
|
-
clause, join = _ordering_for(criterion, fields, ignore_case=folded)
|
|
1023
|
+
clause, join = _ordering_for(criterion, fields, ignore_case=folded, model=model)
|
|
1022
1024
|
clauses.append(_with_nulls(clause, nulls))
|
|
1023
1025
|
if join is not None:
|
|
1024
1026
|
target, onclause, outer = join
|
|
@@ -1033,6 +1035,7 @@ def _ordering_for(
|
|
|
1033
1035
|
fields: Mapping[str, Any],
|
|
1034
1036
|
*,
|
|
1035
1037
|
ignore_case: bool | set[str],
|
|
1038
|
+
model: type[Any] | None = None,
|
|
1036
1039
|
) -> tuple[Any, Any]:
|
|
1037
1040
|
"""Return the clause a criterion stands for, and the table it needs."""
|
|
1038
1041
|
if isinstance(criterion, OrderBy):
|
|
@@ -1045,7 +1048,7 @@ def _ordering_for(
|
|
|
1045
1048
|
if isinstance(field, OrderBy):
|
|
1046
1049
|
column, join = field.expression, (field.join, field.on, field.outer)
|
|
1047
1050
|
else:
|
|
1048
|
-
column, join = field, _join_for(field)
|
|
1051
|
+
column, join = field, _join_for(field, model)
|
|
1049
1052
|
if ignore_case is True or (ignore_case is not False and name in ignore_case):
|
|
1050
1053
|
column = _case_insensitive(column)
|
|
1051
1054
|
return _sort_clause(column, descending=descending, nulls=nulls), join
|
|
@@ -1164,19 +1167,40 @@ def _flatten(criteria: Iterable[Any]) -> Iterator[Any]:
|
|
|
1164
1167
|
yield criterion
|
|
1165
1168
|
|
|
1166
1169
|
|
|
1167
|
-
def _join_for(
|
|
1168
|
-
|
|
1170
|
+
def _join_for(
|
|
1171
|
+
field: Any, # noqa: ANN401
|
|
1172
|
+
model: type[Any] | None,
|
|
1173
|
+
) -> tuple[Any, None, bool] | None:
|
|
1174
|
+
"""Return what to join for a field that is a plain column of another table.
|
|
1169
1175
|
|
|
1170
|
-
A
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1176
|
+
A relationship of the model that reaches that table is the join, condition
|
|
1177
|
+
and all, which is what a view with no foreign key needs. Failing that, the
|
|
1178
|
+
table itself, and `SQLAlchemy` works the condition out from the key.
|
|
1179
|
+
|
|
1180
|
+
An expression may name several tables or none, so it is left alone:
|
|
1181
|
+
`OrderBy` says what to join for those, as it does for an alias, a subquery,
|
|
1182
|
+
or a table two relationships reach.
|
|
1174
1183
|
"""
|
|
1175
1184
|
column = _as_column(field)
|
|
1176
1185
|
if not isinstance(column, sa.Column):
|
|
1177
1186
|
return None
|
|
1178
1187
|
table = getattr(column, "table", None)
|
|
1179
|
-
|
|
1188
|
+
if table is None:
|
|
1189
|
+
return None
|
|
1190
|
+
return (_relationship_to(model, table) or table, None, True)
|
|
1191
|
+
|
|
1192
|
+
|
|
1193
|
+
def _relationship_to(model: type[Any] | None, table: Any) -> Any: # noqa: ANN401
|
|
1194
|
+
"""Return the model's one relationship that reaches this table, if there is one."""
|
|
1195
|
+
mapper = None if model is None else sa.inspect(model, raiseerr=False)
|
|
1196
|
+
if mapper is None:
|
|
1197
|
+
return None
|
|
1198
|
+
reaching = [
|
|
1199
|
+
getattr(model, relationship.key)
|
|
1200
|
+
for relationship in mapper.relationships
|
|
1201
|
+
if relationship.entity.persist_selectable is table
|
|
1202
|
+
]
|
|
1203
|
+
return reaching[0] if len(reaching) == 1 else None
|
|
1180
1204
|
|
|
1181
1205
|
|
|
1182
1206
|
def _reject_conflicting_join(
|
|
@@ -46,7 +46,7 @@ class SQL:
|
|
|
46
46
|
def __repr__(self) -> str:
|
|
47
47
|
return f"{type(self).__name__}({self.db!r})"
|
|
48
48
|
|
|
49
|
-
def __call__(self, template: str, **context: Any) -> SQLQuery: # noqa: ANN401
|
|
49
|
+
def __call__(self, template: str, /, **context: Any) -> SQLQuery: # noqa: ANN401
|
|
50
50
|
"""Read the rows of a template. Short for `from_file`.
|
|
51
51
|
|
|
52
52
|
```python
|
|
@@ -55,7 +55,7 @@ class SQL:
|
|
|
55
55
|
"""
|
|
56
56
|
return self.from_file(template, **context)
|
|
57
57
|
|
|
58
|
-
def from_file(self, template: str, **context: Any) -> SQLQuery: # noqa: ANN401
|
|
58
|
+
def from_file(self, template: str, /, **context: Any) -> SQLQuery: # noqa: ANN401
|
|
59
59
|
"""Read the rows of a template kept under the database's ``templates=``.
|
|
60
60
|
|
|
61
61
|
```python
|
|
@@ -66,7 +66,7 @@ class SQL:
|
|
|
66
66
|
"""
|
|
67
67
|
return SQLQuery(self.db, template, context)
|
|
68
68
|
|
|
69
|
-
def from_string(self, source: str, **context: Any) -> SQLQuery: # noqa: ANN401
|
|
69
|
+
def from_string(self, source: str, /, **context: Any) -> SQLQuery: # noqa: ANN401
|
|
70
70
|
"""Read the rows of SQL written out here rather than kept in a file.
|
|
71
71
|
|
|
72
72
|
```python
|
|
@@ -45,7 +45,7 @@ class SQL:
|
|
|
45
45
|
def __repr__(self) -> str:
|
|
46
46
|
return f"{type(self).__name__}({self.db!r})"
|
|
47
47
|
|
|
48
|
-
def __call__(self, template: str, **context: Any) -> SQLQuery: # noqa: ANN401
|
|
48
|
+
def __call__(self, template: str, /, **context: Any) -> SQLQuery: # noqa: ANN401
|
|
49
49
|
"""Read the rows of a template. Short for `from_file`.
|
|
50
50
|
|
|
51
51
|
```python
|
|
@@ -54,7 +54,7 @@ class SQL:
|
|
|
54
54
|
"""
|
|
55
55
|
return self.from_file(template, **context)
|
|
56
56
|
|
|
57
|
-
def from_file(self, template: str, **context: Any) -> SQLQuery: # noqa: ANN401
|
|
57
|
+
def from_file(self, template: str, /, **context: Any) -> SQLQuery: # noqa: ANN401
|
|
58
58
|
"""Read the rows of a template kept under the database's ``templates=``.
|
|
59
59
|
|
|
60
60
|
```python
|
|
@@ -65,7 +65,7 @@ class SQL:
|
|
|
65
65
|
"""
|
|
66
66
|
return SQLQuery(self.db, template, context)
|
|
67
67
|
|
|
68
|
-
def from_string(self, source: str, **context: Any) -> SQLQuery: # noqa: ANN401
|
|
68
|
+
def from_string(self, source: str, /, **context: Any) -> SQLQuery: # noqa: ANN401
|
|
69
69
|
"""Read the rows of SQL written out here rather than kept in a file.
|
|
70
70
|
|
|
71
71
|
```python
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|