sql-athame 0.4.0a6__py3-none-any.whl → 0.4.0a7__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.
- sql_athame/dataclasses.py +47 -13
- {sql_athame-0.4.0a6.dist-info → sql_athame-0.4.0a7.dist-info}/METADATA +1 -1
- {sql_athame-0.4.0a6.dist-info → sql_athame-0.4.0a7.dist-info}/RECORD +5 -5
- {sql_athame-0.4.0a6.dist-info → sql_athame-0.4.0a7.dist-info}/LICENSE +0 -0
- {sql_athame-0.4.0a6.dist-info → sql_athame-0.4.0a7.dist-info}/WHEEL +0 -0
sql_athame/dataclasses.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import datetime
|
2
|
+
import functools
|
2
3
|
import uuid
|
3
4
|
from collections.abc import AsyncGenerator, Iterable, Mapping
|
4
5
|
from dataclasses import Field, InitVar, dataclass, fields
|
@@ -29,27 +30,56 @@ Pool: TypeAlias = Any
|
|
29
30
|
|
30
31
|
@dataclass
|
31
32
|
class ColumnInfo:
|
32
|
-
type: str
|
33
|
-
create_type: str =
|
34
|
-
nullable: bool =
|
33
|
+
type: Optional[str] = None
|
34
|
+
create_type: Optional[str] = None
|
35
|
+
nullable: Optional[bool] = None
|
35
36
|
_constraints: tuple[str, ...] = ()
|
36
37
|
|
37
38
|
constraints: InitVar[Union[str, Iterable[str], None]] = None
|
38
39
|
|
39
40
|
def __post_init__(self, constraints: Union[str, Iterable[str], None]) -> None:
|
40
|
-
if self.create_type == "":
|
41
|
-
self.create_type = self.type
|
42
|
-
self.type = sql_create_type_map.get(self.type.upper(), self.type)
|
43
41
|
if constraints is not None:
|
44
42
|
if type(constraints) is str:
|
45
43
|
constraints = (constraints,)
|
46
44
|
self._constraints = tuple(constraints)
|
47
45
|
|
46
|
+
@staticmethod
|
47
|
+
def merge(a: "ColumnInfo", b: "ColumnInfo") -> "ColumnInfo":
|
48
|
+
return ColumnInfo(
|
49
|
+
type=b.type if b.type is not None else a.type,
|
50
|
+
create_type=b.create_type if b.create_type is not None else a.create_type,
|
51
|
+
nullable=b.nullable if b.nullable is not None else a.nullable,
|
52
|
+
_constraints=(*a._constraints, *b._constraints),
|
53
|
+
)
|
54
|
+
|
55
|
+
|
56
|
+
@dataclass
|
57
|
+
class ConcreteColumnInfo:
|
58
|
+
type: str
|
59
|
+
create_type: str
|
60
|
+
nullable: bool
|
61
|
+
constraints: tuple[str, ...]
|
62
|
+
|
63
|
+
@staticmethod
|
64
|
+
def from_column_info(name: str, *args: ColumnInfo) -> "ConcreteColumnInfo":
|
65
|
+
info = functools.reduce(ColumnInfo.merge, args, ColumnInfo())
|
66
|
+
if info.create_type is None and info.type is not None:
|
67
|
+
info.create_type = info.type
|
68
|
+
info.type = sql_create_type_map.get(info.type.upper(), info.type)
|
69
|
+
if type(info.type) is not str or type(info.create_type) is not str:
|
70
|
+
raise ValueError(f"Missing SQL type for column {name!r}")
|
71
|
+
return ConcreteColumnInfo(
|
72
|
+
type=info.type,
|
73
|
+
create_type=info.create_type,
|
74
|
+
nullable=bool(info.nullable),
|
75
|
+
constraints=info._constraints,
|
76
|
+
)
|
77
|
+
|
48
78
|
def create_table_string(self) -> str:
|
49
79
|
parts = (
|
50
80
|
self.create_type,
|
51
81
|
*(() if self.nullable else ("NOT NULL",)),
|
52
|
-
*self.
|
82
|
+
*self.constraints,
|
53
83
|
)
|
54
84
|
return " ".join(parts)
|
55
85
|
|
@@ -86,7 +116,7 @@ U = TypeVar("U")
|
|
86
116
|
|
87
117
|
|
88
118
|
class ModelBase:
|
89
|
-
_column_info: Optional[dict[str,
|
119
|
+
_column_info: Optional[dict[str, ConcreteColumnInfo]]
|
90
120
|
_cache: dict[tuple, Any]
|
91
121
|
table_name: str
|
92
122
|
primary_key_names: tuple[str, ...]
|
@@ -138,19 +168,23 @@ class ModelBase:
|
|
138
168
|
return cls._type_hints
|
139
169
|
|
140
170
|
@classmethod
|
141
|
-
def column_info_for_field(cls, field: Field) ->
|
171
|
+
def column_info_for_field(cls, field: Field) -> ConcreteColumnInfo:
|
142
172
|
type_info = cls.type_hints()[field.name]
|
143
173
|
base_type = type_info
|
144
174
|
if get_origin(type_info) is Annotated:
|
145
175
|
base_type = type_info.__origin__ # type: ignore
|
176
|
+
info = []
|
177
|
+
if base_type in sql_type_map:
|
178
|
+
_type, nullable = sql_type_map[base_type]
|
179
|
+
info.append(ColumnInfo(type=_type, nullable=nullable))
|
180
|
+
if get_origin(type_info) is Annotated:
|
146
181
|
for md in type_info.__metadata__: # type: ignore
|
147
182
|
if isinstance(md, ColumnInfo):
|
148
|
-
|
149
|
-
|
150
|
-
return ColumnInfo(type=type, nullable=nullable)
|
183
|
+
info.append(md)
|
184
|
+
return ConcreteColumnInfo.from_column_info(field.name, *info)
|
151
185
|
|
152
186
|
@classmethod
|
153
|
-
def column_info(cls, column: str) ->
|
187
|
+
def column_info(cls, column: str) -> ConcreteColumnInfo:
|
154
188
|
try:
|
155
189
|
return cls._column_info[column] # type: ignore
|
156
190
|
except AttributeError:
|
@@ -1,11 +1,11 @@
|
|
1
1
|
sql_athame/__init__.py,sha256=7OBIMZOcrD2pvfIL-rjD1IGZ3TNQbwyu76a9PWk-yYg,79
|
2
2
|
sql_athame/base.py,sha256=FR7EmC0VkX1VRgvAutSEfYSWhlEYpoqS1Kqxp1jHp6Y,10293
|
3
|
-
sql_athame/dataclasses.py,sha256=
|
3
|
+
sql_athame/dataclasses.py,sha256=8JDACQr5RCeCbu2QRAzA9rpM9i1TJNGKEFXEFbGJUgo,22193
|
4
4
|
sql_athame/escape.py,sha256=kK101xXeFitlvuG-L_hvhdpgGJCtmRTprsn1yEfZKws,758
|
5
5
|
sql_athame/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
6
|
sql_athame/sqlalchemy.py,sha256=aWopfPh3j71XwKmcN_VcHRNlhscI0Sckd4AiyGf8Tpw,1293
|
7
7
|
sql_athame/types.py,sha256=FQ06l9Uc-vo57UrAarvnukILdV2gN1IaYUnHJ_bNYic,475
|
8
|
-
sql_athame-0.4.
|
9
|
-
sql_athame-0.4.
|
10
|
-
sql_athame-0.4.
|
11
|
-
sql_athame-0.4.
|
8
|
+
sql_athame-0.4.0a7.dist-info/LICENSE,sha256=xqV29vPFqITcKifYrGPgVIBjq4fdmLSwY3gRUtDKafg,1076
|
9
|
+
sql_athame-0.4.0a7.dist-info/METADATA,sha256=OqUSaxi_5K6vfYxWpiXGP_qDXPU-qQnCrkY3yruhzi4,12845
|
10
|
+
sql_athame-0.4.0a7.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
11
|
+
sql_athame-0.4.0a7.dist-info/RECORD,,
|
File without changes
|
File without changes
|