pydoptic-sql 0.0.1.post1.dev2__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.
- pydoptic_sql/__init__.py +49 -0
- pydoptic_sql/py.typed +0 -0
- pydoptic_sql/sql_computed.py +93 -0
- pydoptic_sql/sql_constraint.py +782 -0
- pydoptic_sql/sql_having.py +728 -0
- pydoptic_sql/sql_order.py +28 -0
- pydoptic_sql/sql_query.py +1144 -0
- pydoptic_sql/sql_service.py +335 -0
- pydoptic_sql/sql_table.py +188 -0
- pydoptic_sql-0.0.1.post1.dev2.dist-info/METADATA +75 -0
- pydoptic_sql-0.0.1.post1.dev2.dist-info/RECORD +14 -0
- pydoptic_sql-0.0.1.post1.dev2.dist-info/WHEEL +5 -0
- pydoptic_sql-0.0.1.post1.dev2.dist-info/licenses/LICENSE +21 -0
- pydoptic_sql-0.0.1.post1.dev2.dist-info/top_level.txt +1 -0
pydoptic_sql/__init__.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from pydoptic_sql.sql_table import (
|
|
2
|
+
AutoIncrement,
|
|
3
|
+
Check,
|
|
4
|
+
ColumnConstraint,
|
|
5
|
+
ColumnInfo,
|
|
6
|
+
ColumnType,
|
|
7
|
+
Default,
|
|
8
|
+
ForeignKey,
|
|
9
|
+
ManualColumnConstraint,
|
|
10
|
+
PrimaryKey,
|
|
11
|
+
SqlTable,
|
|
12
|
+
Unique,
|
|
13
|
+
column,
|
|
14
|
+
)
|
|
15
|
+
from pydoptic_sql.sql_constraint import Comparison, Constraint, Constraint2, Constraint3, Constraint4
|
|
16
|
+
from pydoptic_sql.sql_order import Direction, OrderBy
|
|
17
|
+
from pydoptic_sql.sql_computed import AggregateFunction, Computed, ComputedResult
|
|
18
|
+
from pydoptic_sql.sql_having import HavingConstraint, HavingConstraint2, HavingConstraint3, HavingConstraint4
|
|
19
|
+
from pydoptic_sql.sql_query import (
|
|
20
|
+
ComputedQuery1,
|
|
21
|
+
ComputedQuery2,
|
|
22
|
+
ComputedQuery3,
|
|
23
|
+
ComputedQuery4,
|
|
24
|
+
CreateQuery,
|
|
25
|
+
DeleteQuery,
|
|
26
|
+
DropQuery,
|
|
27
|
+
InsertQuery,
|
|
28
|
+
JoinType,
|
|
29
|
+
Query1,
|
|
30
|
+
Query2,
|
|
31
|
+
Query3,
|
|
32
|
+
Query4,
|
|
33
|
+
SqlQuery,
|
|
34
|
+
UpdateQuery,
|
|
35
|
+
)
|
|
36
|
+
from pydoptic_sql.sql_service import PsycoPgSqlClient, SqlClient, SqlResponse, SqlTransaction
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
'AutoIncrement', 'Check', 'ColumnConstraint', 'ColumnInfo', 'ColumnType', 'Default', 'ForeignKey',
|
|
40
|
+
'ManualColumnConstraint', 'PrimaryKey', 'SqlTable', 'Unique', 'column',
|
|
41
|
+
'Comparison', 'Constraint', 'Constraint2', 'Constraint3', 'Constraint4',
|
|
42
|
+
'Direction', 'OrderBy',
|
|
43
|
+
'AggregateFunction', 'Computed', 'ComputedResult',
|
|
44
|
+
'HavingConstraint', 'HavingConstraint2', 'HavingConstraint3', 'HavingConstraint4',
|
|
45
|
+
'ComputedQuery1', 'ComputedQuery2', 'ComputedQuery3', 'ComputedQuery4',
|
|
46
|
+
'CreateQuery', 'DeleteQuery', 'DropQuery', 'InsertQuery', 'JoinType',
|
|
47
|
+
'Query1', 'Query2', 'Query3', 'Query4', 'SqlQuery', 'UpdateQuery',
|
|
48
|
+
'PsycoPgSqlClient', 'SqlClient', 'SqlResponse', 'SqlTransaction',
|
|
49
|
+
]
|
pydoptic_sql/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Any, Dict, Generic, Mapping, Type, TypeVar
|
|
5
|
+
|
|
6
|
+
from pydoptic.selector import Prop, PropOpt, SelectVal, SelectValue, Selectable
|
|
7
|
+
from pydoptic_sql import SqlTable
|
|
8
|
+
|
|
9
|
+
TC = TypeVar('TC', bound=SqlTable, contravariant=True)
|
|
10
|
+
A = TypeVar('A')
|
|
11
|
+
|
|
12
|
+
class AggregateFunction(Enum):
|
|
13
|
+
SUM = 'SUM'
|
|
14
|
+
COUNT = 'COUNT'
|
|
15
|
+
AVG = 'AVG'
|
|
16
|
+
MIN = 'MIN'
|
|
17
|
+
MAX = 'MAX'
|
|
18
|
+
|
|
19
|
+
class ComputedResult(Selectable['ComputedResult']):
|
|
20
|
+
"""
|
|
21
|
+
Dict-backed holder for the computed (aggregate) columns of a query result row, keyed by each
|
|
22
|
+
`Computed`'s alias. Mirrors `PartialModel`'s shape but isn't backed by a model class -- there's
|
|
23
|
+
no schema behind an aggregate expression, just whatever aliases the query selected.
|
|
24
|
+
"""
|
|
25
|
+
__slots__ = ['_dict']
|
|
26
|
+
_dict: Dict[str, Any]
|
|
27
|
+
|
|
28
|
+
def __init__(self, **kwargs: Any):
|
|
29
|
+
object.__setattr__(self, '_dict', dict(kwargs))
|
|
30
|
+
|
|
31
|
+
def __repr__(self) -> str:
|
|
32
|
+
return 'ComputedResult(' + ', '.join(f'{k}={v}' for k, v in self._dict.items()) + ')'
|
|
33
|
+
|
|
34
|
+
def __eq__(self, other: object) -> bool:
|
|
35
|
+
return isinstance(other, ComputedResult) and self._dict == other._dict
|
|
36
|
+
|
|
37
|
+
def __getattr__(self, item: str) -> Any:
|
|
38
|
+
try:
|
|
39
|
+
return object.__getattribute__(self, '_dict')[item]
|
|
40
|
+
except KeyError:
|
|
41
|
+
raise AttributeError(item)
|
|
42
|
+
|
|
43
|
+
def as_dict(self) -> Mapping[str, Any]:
|
|
44
|
+
return self._dict
|
|
45
|
+
|
|
46
|
+
@dataclass(frozen=True, slots=True)
|
|
47
|
+
class Computed(Generic[TC, A], SelectVal[ComputedResult, A]):
|
|
48
|
+
"""
|
|
49
|
+
An aggregate expression (SUM/COUNT/AVG/MIN/MAX) over a column, constructed via `SqlQuery.sum`/
|
|
50
|
+
`.count`/etc., selected into a query via `select_computed`/`select_computed_more`, and extracted
|
|
51
|
+
from a `ComputedResult` via `get_val`/`get_val_safe` -- same as a plain `Prop` extracts a value
|
|
52
|
+
from a model. `column` is `None` only for `SqlQuery.count(table)` (`COUNT(*)`), which doesn't
|
|
53
|
+
reference any particular column.
|
|
54
|
+
|
|
55
|
+
`TC` is phantom bookkeeping, not part of the `Select[ComputedResult, A]` shape it's used as --
|
|
56
|
+
it exists purely so `select_computed_more`'s signature can restrict which joined table(s) a given
|
|
57
|
+
`Computed` may reference, the same way `OrderBy`'s `TC` does. Like `OrderBy`, `Computed` has no
|
|
58
|
+
arity variants of its own: a joined query's computed selection is typed as a union of
|
|
59
|
+
`Computed[<each joined table>, Any]`, so an entry set for one table stays valid unchanged as more
|
|
60
|
+
tables get joined in, and qualification (`table.column` vs. bare) is decided by whichever class
|
|
61
|
+
renders it, not by `Computed` itself.
|
|
62
|
+
"""
|
|
63
|
+
column: Prop[TC, Any] | PropOpt[TC, Any] | None
|
|
64
|
+
function: AggregateFunction
|
|
65
|
+
label: str
|
|
66
|
+
_target: Type[A]
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def origin(self) -> Type[ComputedResult]:
|
|
70
|
+
return ComputedResult
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def target(self) -> Type[A]:
|
|
74
|
+
return self._target
|
|
75
|
+
|
|
76
|
+
def get_unsafe(self, value: 'Selectable[ComputedResult] | Dict[str, Any]') -> SelectValue[A]:
|
|
77
|
+
if isinstance(value, dict):
|
|
78
|
+
if self.label not in value:
|
|
79
|
+
raise ValueError(f'Unexpected empty value for computed column {self.label}')
|
|
80
|
+
result = value[self.label]
|
|
81
|
+
else:
|
|
82
|
+
try:
|
|
83
|
+
result = getattr(value, self.label)
|
|
84
|
+
except AttributeError:
|
|
85
|
+
raise ValueError(f'Unexpected empty value for computed column {self.label}')
|
|
86
|
+
return SelectValue(result, False, False)
|
|
87
|
+
|
|
88
|
+
def get(self, value: ComputedResult) -> SelectValue[A]:
|
|
89
|
+
return SelectValue(getattr(value, self.label), False, False)
|
|
90
|
+
|
|
91
|
+
def to_sql(self) -> str:
|
|
92
|
+
col_ref = '*' if self.column is None else self.column.label
|
|
93
|
+
return f'{self.function.value}({col_ref}) AS {self.label}'
|