omlish 0.0.0.dev70__py3-none-any.whl → 0.0.0.dev72__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- omlish/__about__.py +3 -3
- omlish/dataclasses/impl/internals.py +1 -0
- omlish/dataclasses/impl/metaclass.py +22 -5
- omlish/dataclasses/impl/params.py +4 -2
- omlish/diag/_pycharm/runhack.py +9 -4
- omlish/formats/json/cli.py +3 -0
- omlish/http/__init__.py +17 -0
- omlish/http/clients.py +239 -0
- omlish/http/consts.py +4 -0
- omlish/http/headers.py +181 -0
- omlish/sql/queries/__init__.py +79 -0
- omlish/sql/queries/base.py +21 -0
- omlish/sql/queries/binary.py +48 -0
- omlish/sql/queries/exprs.py +54 -0
- omlish/sql/queries/idents.py +29 -0
- omlish/sql/queries/multi.py +41 -0
- omlish/sql/queries/names.py +34 -0
- omlish/sql/queries/relations.py +39 -0
- omlish/sql/queries/selects.py +50 -0
- omlish/sql/queries/std.py +29 -0
- omlish/sql/queries/stmts.py +28 -0
- omlish/sql/queries/unary.py +29 -0
- omlish/sql/tabledefs/__init__.py +11 -0
- omlish/sql/tabledefs/alchemy.py +26 -0
- omlish/sql/tabledefs/dtypes.py +22 -0
- omlish/sql/tabledefs/elements.py +88 -0
- omlish/sql/tabledefs/lower.py +49 -0
- omlish/sql/tabledefs/marshal.py +19 -0
- omlish/sql/tabledefs/tabledefs.py +52 -0
- {omlish-0.0.0.dev70.dist-info → omlish-0.0.0.dev72.dist-info}/METADATA +3 -3
- {omlish-0.0.0.dev70.dist-info → omlish-0.0.0.dev72.dist-info}/RECORD +35 -14
- {omlish-0.0.0.dev70.dist-info → omlish-0.0.0.dev72.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev70.dist-info → omlish-0.0.0.dev72.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev70.dist-info → omlish-0.0.0.dev72.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev70.dist-info → omlish-0.0.0.dev72.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ... import dataclasses as dc
|
4
|
+
from ... import lang
|
5
|
+
|
6
|
+
|
7
|
+
##
|
8
|
+
|
9
|
+
|
10
|
+
Value: ta.TypeAlias = ta.Any
|
11
|
+
|
12
|
+
|
13
|
+
##
|
14
|
+
|
15
|
+
|
16
|
+
class Node(dc.Frozen, lang.Abstract, cache_hash=True):
|
17
|
+
pass
|
18
|
+
|
19
|
+
|
20
|
+
class Builder(lang.Abstract):
|
21
|
+
pass
|
@@ -0,0 +1,48 @@
|
|
1
|
+
from ... import check
|
2
|
+
from ... import lang
|
3
|
+
from .base import Node
|
4
|
+
from .exprs import CanExpr
|
5
|
+
from .exprs import Expr
|
6
|
+
from .exprs import ExprBuilder
|
7
|
+
|
8
|
+
|
9
|
+
##
|
10
|
+
|
11
|
+
|
12
|
+
class BinaryOp(Node, lang.Final):
|
13
|
+
name: str
|
14
|
+
|
15
|
+
|
16
|
+
class BinaryOps(lang.Namespace):
|
17
|
+
ADD = BinaryOp('add')
|
18
|
+
SUB = BinaryOp('sub')
|
19
|
+
|
20
|
+
EQ = BinaryOp('eq')
|
21
|
+
NE = BinaryOp('ne')
|
22
|
+
|
23
|
+
|
24
|
+
class Binary(Expr, lang.Final):
|
25
|
+
op: BinaryOp
|
26
|
+
l: Expr
|
27
|
+
r: Expr
|
28
|
+
|
29
|
+
|
30
|
+
class BinaryBuilder(ExprBuilder):
|
31
|
+
def binary(self, op: BinaryOp, *es: CanExpr) -> Expr:
|
32
|
+
check.not_empty(es)
|
33
|
+
l = self.expr(es[0])
|
34
|
+
for r in es[1:]:
|
35
|
+
l = Binary(op, l, self.expr(r))
|
36
|
+
return l
|
37
|
+
|
38
|
+
def add(self, *es: CanExpr) -> Expr:
|
39
|
+
return self.binary(BinaryOps.ADD, *es)
|
40
|
+
|
41
|
+
def sub(self, *es: CanExpr) -> Expr:
|
42
|
+
return self.binary(BinaryOps.SUB, *es)
|
43
|
+
|
44
|
+
def eq(self, *es: CanExpr) -> Expr:
|
45
|
+
return self.binary(BinaryOps.EQ, *es)
|
46
|
+
|
47
|
+
def ne(self, *es: CanExpr) -> Expr:
|
48
|
+
return self.binary(BinaryOps.NE, *es)
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ... import lang
|
4
|
+
from .base import Node
|
5
|
+
from .base import Value
|
6
|
+
from .idents import Ident
|
7
|
+
from .names import CanName
|
8
|
+
from .names import Name
|
9
|
+
from .names import NameBuilder
|
10
|
+
|
11
|
+
|
12
|
+
##
|
13
|
+
|
14
|
+
|
15
|
+
class Expr(Node, lang.Abstract):
|
16
|
+
pass
|
17
|
+
|
18
|
+
|
19
|
+
class Literal(Expr, lang.Final):
|
20
|
+
v: Value
|
21
|
+
|
22
|
+
|
23
|
+
class NameExpr(Expr, lang.Final):
|
24
|
+
n: Name
|
25
|
+
|
26
|
+
|
27
|
+
CanLiteral: ta.TypeAlias = Literal | Value
|
28
|
+
CanExpr: ta.TypeAlias = Expr | CanName | CanLiteral
|
29
|
+
|
30
|
+
|
31
|
+
class ExprBuilder(NameBuilder):
|
32
|
+
def literal(self, o: CanLiteral) -> Literal:
|
33
|
+
if isinstance(o, Literal):
|
34
|
+
return o
|
35
|
+
elif isinstance(o, Node):
|
36
|
+
raise TypeError(o)
|
37
|
+
else:
|
38
|
+
return Literal(o)
|
39
|
+
|
40
|
+
@ta.final
|
41
|
+
def l(self, o: CanLiteral) -> Literal: # noqa
|
42
|
+
return self.literal(o)
|
43
|
+
|
44
|
+
def expr(self, o: CanExpr) -> Expr:
|
45
|
+
if isinstance(o, Expr):
|
46
|
+
return o
|
47
|
+
elif isinstance(o, (Name, Ident)):
|
48
|
+
return NameExpr(self.name(o))
|
49
|
+
else:
|
50
|
+
return self.literal(o)
|
51
|
+
|
52
|
+
@ta.final
|
53
|
+
def e(self, o: CanExpr) -> Expr:
|
54
|
+
return self.expr(o)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ... import lang
|
4
|
+
from .base import Builder
|
5
|
+
from .base import Node
|
6
|
+
|
7
|
+
|
8
|
+
##
|
9
|
+
|
10
|
+
|
11
|
+
class Ident(Node, lang.Final):
|
12
|
+
s: str
|
13
|
+
|
14
|
+
|
15
|
+
CanIdent: ta.TypeAlias = Ident | str
|
16
|
+
|
17
|
+
|
18
|
+
class IdentBuilder(Builder):
|
19
|
+
def ident(self, o: CanIdent) -> Ident:
|
20
|
+
if isinstance(o, Ident):
|
21
|
+
return o
|
22
|
+
elif isinstance(o, str):
|
23
|
+
return Ident(o)
|
24
|
+
else:
|
25
|
+
raise TypeError(o)
|
26
|
+
|
27
|
+
@ta.final
|
28
|
+
def i(self, o: CanIdent) -> Ident:
|
29
|
+
return self.ident(o)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ... import check
|
4
|
+
from ... import dataclasses as dc
|
5
|
+
from ... import lang
|
6
|
+
from .base import Node
|
7
|
+
from .exprs import CanExpr
|
8
|
+
from .exprs import Expr
|
9
|
+
from .exprs import ExprBuilder
|
10
|
+
|
11
|
+
|
12
|
+
##
|
13
|
+
|
14
|
+
|
15
|
+
class MultiOp(Node, lang.Final):
|
16
|
+
name: str
|
17
|
+
|
18
|
+
|
19
|
+
class MultiOps(lang.Namespace):
|
20
|
+
AND = MultiOp('and')
|
21
|
+
OR = MultiOp('or')
|
22
|
+
|
23
|
+
|
24
|
+
class Multi(Expr, lang.Final):
|
25
|
+
op: MultiOp
|
26
|
+
es: ta.Sequence[Expr] = dc.xfield(coerce=tuple)
|
27
|
+
|
28
|
+
|
29
|
+
class MultiBuilder(ExprBuilder):
|
30
|
+
def multi(self, op: MultiOp, *es: CanExpr) -> Expr:
|
31
|
+
check.not_empty(es)
|
32
|
+
if len(es) == 1:
|
33
|
+
return self.expr(es[0])
|
34
|
+
else:
|
35
|
+
return Multi(op, [self.expr(e) for e in es])
|
36
|
+
|
37
|
+
def and_(self, *es: CanExpr) -> Expr:
|
38
|
+
return self.multi(MultiOps.AND, *es)
|
39
|
+
|
40
|
+
def or_(self, *es: CanExpr) -> Expr:
|
41
|
+
return self.multi(MultiOps.OR, *es)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ... import dataclasses as dc
|
4
|
+
from ... import lang
|
5
|
+
from .base import Node
|
6
|
+
from .idents import CanIdent
|
7
|
+
from .idents import Ident
|
8
|
+
from .idents import IdentBuilder
|
9
|
+
|
10
|
+
|
11
|
+
##
|
12
|
+
|
13
|
+
|
14
|
+
class Name(Node, lang.Final):
|
15
|
+
ps: ta.Sequence[Ident] = dc.xfield(coerce=tuple)
|
16
|
+
|
17
|
+
|
18
|
+
CanName: ta.TypeAlias = Name | CanIdent | ta.Sequence[CanIdent]
|
19
|
+
|
20
|
+
|
21
|
+
class NameBuilder(IdentBuilder):
|
22
|
+
def name(self, o: CanName) -> Name:
|
23
|
+
if isinstance(o, Name):
|
24
|
+
return o
|
25
|
+
elif isinstance(o, (Ident, str)):
|
26
|
+
return Name([self.ident(o)])
|
27
|
+
elif isinstance(o, ta.Sequence):
|
28
|
+
return Name([self.ident(p) for p in o])
|
29
|
+
else:
|
30
|
+
raise TypeError(o)
|
31
|
+
|
32
|
+
@ta.final
|
33
|
+
def n(self, o: CanName) -> Name:
|
34
|
+
return self.name(o)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ... import dataclasses as dc
|
4
|
+
from ... import lang
|
5
|
+
from .base import Node
|
6
|
+
from .idents import Ident
|
7
|
+
from .names import CanName
|
8
|
+
from .names import Name
|
9
|
+
from .names import NameBuilder
|
10
|
+
|
11
|
+
|
12
|
+
##
|
13
|
+
|
14
|
+
|
15
|
+
class Relation(Node, lang.Abstract):
|
16
|
+
pass
|
17
|
+
|
18
|
+
|
19
|
+
class Table(Relation, lang.Final):
|
20
|
+
n: Name
|
21
|
+
a: Ident | None = dc.xfield(None, repr_fn=dc.opt_repr)
|
22
|
+
|
23
|
+
|
24
|
+
CanTable: ta.TypeAlias = Table | CanName
|
25
|
+
CanRelation: ta.TypeAlias = Relation | CanTable
|
26
|
+
|
27
|
+
|
28
|
+
class RelationBuilder(NameBuilder):
|
29
|
+
def table(self, n: CanTable) -> Table:
|
30
|
+
if isinstance(n, Table):
|
31
|
+
return n
|
32
|
+
else:
|
33
|
+
return Table(self.name(n))
|
34
|
+
|
35
|
+
def relation(self, o: CanRelation) -> Relation:
|
36
|
+
if isinstance(o, Relation):
|
37
|
+
return o
|
38
|
+
else:
|
39
|
+
return self.table(o)
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ... import dataclasses as dc
|
4
|
+
from ... import lang
|
5
|
+
from .base import Node
|
6
|
+
from .exprs import CanExpr
|
7
|
+
from .exprs import Expr
|
8
|
+
from .exprs import ExprBuilder
|
9
|
+
from .idents import Ident
|
10
|
+
from .relations import CanRelation
|
11
|
+
from .relations import Relation
|
12
|
+
from .relations import RelationBuilder
|
13
|
+
from .stmts import Stmt
|
14
|
+
|
15
|
+
|
16
|
+
##
|
17
|
+
|
18
|
+
|
19
|
+
class SelectItem(Node, lang.Final):
|
20
|
+
v: Expr
|
21
|
+
a: Ident | None = dc.xfield(None, repr_fn=dc.opt_repr)
|
22
|
+
|
23
|
+
|
24
|
+
class Select(Stmt, lang.Final):
|
25
|
+
its: ta.Sequence[SelectItem] = dc.xfield(coerce=tuple)
|
26
|
+
fr: Relation | None = dc.xfield(None, repr_fn=dc.opt_repr)
|
27
|
+
wh: Expr | None = dc.xfield(None, repr_fn=dc.opt_repr)
|
28
|
+
|
29
|
+
|
30
|
+
CanSelectItem: ta.TypeAlias = SelectItem | CanExpr
|
31
|
+
|
32
|
+
|
33
|
+
class SelectBuilder(ExprBuilder, RelationBuilder):
|
34
|
+
def select_item(self, o: CanSelectItem) -> SelectItem:
|
35
|
+
if isinstance(o, SelectItem):
|
36
|
+
return o
|
37
|
+
else:
|
38
|
+
return SelectItem(self.expr(o))
|
39
|
+
|
40
|
+
def select(
|
41
|
+
self,
|
42
|
+
its: ta.Sequence[CanSelectItem],
|
43
|
+
fr: CanRelation | None = None,
|
44
|
+
wh: CanExpr | None = None,
|
45
|
+
) -> Select:
|
46
|
+
return Select(
|
47
|
+
[self.select_item(i) for i in its],
|
48
|
+
fr=self.relation(fr) if fr is not None else None,
|
49
|
+
wh=self.expr(wh) if wh is not None else None,
|
50
|
+
)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
from .base import Builder
|
2
|
+
from .binary import BinaryBuilder
|
3
|
+
from .exprs import ExprBuilder
|
4
|
+
from .idents import IdentBuilder
|
5
|
+
from .multi import MultiBuilder
|
6
|
+
from .names import NameBuilder
|
7
|
+
from .relations import RelationBuilder
|
8
|
+
from .selects import SelectBuilder
|
9
|
+
from .stmts import StmtBuilder
|
10
|
+
from .unary import UnaryBuilder
|
11
|
+
|
12
|
+
|
13
|
+
class StdBuilder(
|
14
|
+
SelectBuilder,
|
15
|
+
StmtBuilder,
|
16
|
+
|
17
|
+
MultiBuilder,
|
18
|
+
BinaryBuilder,
|
19
|
+
UnaryBuilder,
|
20
|
+
ExprBuilder,
|
21
|
+
|
22
|
+
RelationBuilder,
|
23
|
+
|
24
|
+
NameBuilder,
|
25
|
+
IdentBuilder,
|
26
|
+
|
27
|
+
Builder,
|
28
|
+
):
|
29
|
+
pass
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ... import lang
|
4
|
+
from .base import Node
|
5
|
+
from .exprs import CanExpr
|
6
|
+
from .exprs import ExprBuilder
|
7
|
+
|
8
|
+
|
9
|
+
##
|
10
|
+
|
11
|
+
|
12
|
+
class Stmt(Node, lang.Abstract):
|
13
|
+
pass
|
14
|
+
|
15
|
+
|
16
|
+
class ExprStmt(Stmt, lang.Final):
|
17
|
+
pass
|
18
|
+
|
19
|
+
|
20
|
+
CanStmt: ta.TypeAlias = Stmt | CanExpr
|
21
|
+
|
22
|
+
|
23
|
+
class StmtBuilder(ExprBuilder):
|
24
|
+
def stmt(self, o: CanStmt) -> Stmt:
|
25
|
+
if isinstance(o, Stmt):
|
26
|
+
return o
|
27
|
+
else:
|
28
|
+
return ExprStmt(self.expr(o))
|
@@ -0,0 +1,29 @@
|
|
1
|
+
from ... import lang
|
2
|
+
from .base import Node
|
3
|
+
from .exprs import CanExpr
|
4
|
+
from .exprs import Expr
|
5
|
+
from .exprs import ExprBuilder
|
6
|
+
|
7
|
+
|
8
|
+
##
|
9
|
+
|
10
|
+
|
11
|
+
class UnaryOp(Node, lang.Final):
|
12
|
+
name: str
|
13
|
+
|
14
|
+
|
15
|
+
class UnaryOps(lang.Namespace):
|
16
|
+
NOT = UnaryOp('not')
|
17
|
+
|
18
|
+
|
19
|
+
class Unary(Expr, lang.Final):
|
20
|
+
op: UnaryOp
|
21
|
+
v: Expr
|
22
|
+
|
23
|
+
|
24
|
+
class UnaryBuilder(ExprBuilder):
|
25
|
+
def unary(self, op: UnaryOp, v: CanExpr) -> Unary:
|
26
|
+
return Unary(op, self.expr(v))
|
27
|
+
|
28
|
+
def not_(self, v: CanExpr) -> Unary:
|
29
|
+
return self.unary(UnaryOps.NOT, v)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
"""
|
2
|
+
TODO:
|
3
|
+
- move to sql/alchemy/tabledefs.py
|
4
|
+
"""
|
5
|
+
import typing as ta
|
6
|
+
|
7
|
+
import sqlalchemy as sa
|
8
|
+
import sqlalchemy.sql.schema
|
9
|
+
|
10
|
+
from .tabledefs import TableDef
|
11
|
+
|
12
|
+
|
13
|
+
def build_sa_table(
|
14
|
+
td: TableDef,
|
15
|
+
*,
|
16
|
+
metadata: sa.MetaData | None = None,
|
17
|
+
**kwargs: ta.Any,
|
18
|
+
) -> sa.Table:
|
19
|
+
items: list[sa.sql.schema.SchemaItem] = []
|
20
|
+
|
21
|
+
return sa.Table(
|
22
|
+
td.name,
|
23
|
+
metadata if metadata is not None else sa.MetaData(),
|
24
|
+
*items,
|
25
|
+
**kwargs,
|
26
|
+
)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from ... import dataclasses as dc
|
2
|
+
from ... import lang
|
3
|
+
|
4
|
+
|
5
|
+
@dc.dataclass(frozen=True)
|
6
|
+
class Dtype(lang.Abstract, lang.Sealed):
|
7
|
+
pass
|
8
|
+
|
9
|
+
|
10
|
+
@dc.dataclass(frozen=True)
|
11
|
+
class Integer(Dtype, lang.Singleton):
|
12
|
+
pass
|
13
|
+
|
14
|
+
|
15
|
+
@dc.dataclass(frozen=True)
|
16
|
+
class String(Dtype, lang.Singleton):
|
17
|
+
pass
|
18
|
+
|
19
|
+
|
20
|
+
@dc.dataclass(frozen=True)
|
21
|
+
class Datetime(Dtype, lang.Singleton):
|
22
|
+
pass
|
@@ -0,0 +1,88 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ... import check
|
4
|
+
from ... import collections as col
|
5
|
+
from ... import dataclasses as dc
|
6
|
+
from ... import lang
|
7
|
+
from .dtypes import Dtype
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
|
12
|
+
|
13
|
+
class Element(lang.Abstract, lang.Sealed):
|
14
|
+
pass
|
15
|
+
|
16
|
+
|
17
|
+
##
|
18
|
+
|
19
|
+
|
20
|
+
@dc.dataclass(frozen=True)
|
21
|
+
class Column(Element, lang.Final):
|
22
|
+
name: str
|
23
|
+
type: Dtype
|
24
|
+
nullable: bool = dc.field(default=False, kw_only=True)
|
25
|
+
default: lang.Maybe[ta.Any] = dc.field(default=lang.empty(), kw_only=True)
|
26
|
+
|
27
|
+
|
28
|
+
@dc.dataclass(frozen=True)
|
29
|
+
class PrimaryKey(Element, lang.Final):
|
30
|
+
columns: ta.Sequence[str]
|
31
|
+
|
32
|
+
|
33
|
+
@dc.dataclass(frozen=True)
|
34
|
+
class Index(Element, lang.Final):
|
35
|
+
columns: ta.Sequence[str] = dc.xfield(coerce=col.seq)
|
36
|
+
name: str | None = None
|
37
|
+
|
38
|
+
|
39
|
+
##
|
40
|
+
|
41
|
+
|
42
|
+
@dc.dataclass(frozen=True)
|
43
|
+
class IdIntegerPrimaryKey(Element, lang.Final):
|
44
|
+
pass
|
45
|
+
|
46
|
+
|
47
|
+
#
|
48
|
+
|
49
|
+
|
50
|
+
@dc.dataclass(frozen=True)
|
51
|
+
class CreatedAt(Element, lang.Final):
|
52
|
+
pass
|
53
|
+
|
54
|
+
|
55
|
+
@dc.dataclass(frozen=True)
|
56
|
+
class UpdatedAt(Element, lang.Final):
|
57
|
+
pass
|
58
|
+
|
59
|
+
|
60
|
+
@dc.dataclass(frozen=True)
|
61
|
+
class UpdatedAtTrigger(Element, lang.Final):
|
62
|
+
column: str
|
63
|
+
|
64
|
+
|
65
|
+
@dc.dataclass(frozen=True)
|
66
|
+
class CreatedAtUpdatedAt(Element, lang.Final):
|
67
|
+
pass
|
68
|
+
|
69
|
+
|
70
|
+
##
|
71
|
+
|
72
|
+
|
73
|
+
@dc.dataclass(frozen=True)
|
74
|
+
class Elements(ta.Sequence[Element], lang.Final):
|
75
|
+
lst: ta.Sequence[Element] = dc.xfield(coerce=col.seq_of(check.of_isinstance(Element)))
|
76
|
+
|
77
|
+
def __iter__(self) -> ta.Iterator[Element]:
|
78
|
+
return iter(self.lst)
|
79
|
+
|
80
|
+
def __getitem__(self, index: ta.Any) -> Element: # type: ignore[override]
|
81
|
+
return self.lst[index]
|
82
|
+
|
83
|
+
def __len__(self) -> int:
|
84
|
+
return len(self.lst)
|
85
|
+
|
86
|
+
@lang.cached_property
|
87
|
+
def by_type(self) -> col.DynamicTypeMap[Element]:
|
88
|
+
return col.DynamicTypeMap(self.lst)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
from ... import dataclasses as dc
|
2
|
+
from .dtypes import Datetime
|
3
|
+
from .dtypes import Integer
|
4
|
+
from .elements import Column
|
5
|
+
from .elements import CreatedAt
|
6
|
+
from .elements import CreatedAtUpdatedAt
|
7
|
+
from .elements import Element
|
8
|
+
from .elements import Elements
|
9
|
+
from .elements import IdIntegerPrimaryKey
|
10
|
+
from .elements import PrimaryKey
|
11
|
+
from .elements import UpdatedAt
|
12
|
+
from .elements import UpdatedAtTrigger
|
13
|
+
from .tabledefs import TableDef
|
14
|
+
|
15
|
+
|
16
|
+
def lower_table_elements(td: TableDef) -> TableDef:
|
17
|
+
todo: list[Element] = list(td.elements)[::-1]
|
18
|
+
out: list[Element] = []
|
19
|
+
|
20
|
+
while todo:
|
21
|
+
match (e := todo.pop()):
|
22
|
+
case Column() | PrimaryKey():
|
23
|
+
out.append(e)
|
24
|
+
|
25
|
+
case IdIntegerPrimaryKey():
|
26
|
+
out.extend([
|
27
|
+
Column('id', Integer()),
|
28
|
+
PrimaryKey(['id']),
|
29
|
+
])
|
30
|
+
|
31
|
+
case CreatedAt():
|
32
|
+
out.append(Column('created_at', Datetime()))
|
33
|
+
|
34
|
+
case UpdatedAt():
|
35
|
+
out.extend([
|
36
|
+
Column('updated_at', Datetime()),
|
37
|
+
UpdatedAtTrigger('updated_at'),
|
38
|
+
])
|
39
|
+
|
40
|
+
case CreatedAtUpdatedAt():
|
41
|
+
todo.extend([
|
42
|
+
CreatedAt(),
|
43
|
+
UpdatedAt(),
|
44
|
+
][::-1])
|
45
|
+
|
46
|
+
case _:
|
47
|
+
raise TypeError(e)
|
48
|
+
|
49
|
+
return dc.replace(td, elements=Elements(out))
|
@@ -0,0 +1,19 @@
|
|
1
|
+
from ... import lang
|
2
|
+
from ... import marshal as msh
|
3
|
+
from .dtypes import Dtype
|
4
|
+
from .elements import Element
|
5
|
+
|
6
|
+
|
7
|
+
def _install_poly(cls: type) -> None:
|
8
|
+
p = msh.polymorphism_from_subclasses(cls, naming=msh.Naming.SNAKE)
|
9
|
+
msh.STANDARD_MARSHALER_FACTORIES[0:0] = [msh.PolymorphismMarshalerFactory(p)]
|
10
|
+
msh.STANDARD_UNMARSHALER_FACTORIES[0:0] = [msh.PolymorphismUnmarshalerFactory(p)]
|
11
|
+
|
12
|
+
|
13
|
+
@lang.cached_function
|
14
|
+
def _install_standard_marshalling() -> None:
|
15
|
+
_install_poly(Dtype)
|
16
|
+
_install_poly(Element)
|
17
|
+
|
18
|
+
|
19
|
+
_install_standard_marshalling()
|
@@ -0,0 +1,52 @@
|
|
1
|
+
"""
|
2
|
+
TODO:
|
3
|
+
- QualifiedName
|
4
|
+
- hybrid dataclass scheme
|
5
|
+
- sqlite without sqlalchemy
|
6
|
+
|
7
|
+
==
|
8
|
+
|
9
|
+
@td.tableclass([
|
10
|
+
IdIntegerPrimaryKey(),
|
11
|
+
CreatedAtUpdatedAt(),
|
12
|
+
])
|
13
|
+
@dc.dataclass(frozen=True)
|
14
|
+
class User(lang.Final):
|
15
|
+
id: int
|
16
|
+
|
17
|
+
created_at: datetime.datetime
|
18
|
+
updated_at: datetime.datetime
|
19
|
+
|
20
|
+
name: str
|
21
|
+
|
22
|
+
==
|
23
|
+
|
24
|
+
@td.tableclass([
|
25
|
+
IdIntegerPrimaryKey(),
|
26
|
+
CreatedAtUpdatedAt(),
|
27
|
+
])
|
28
|
+
@dc.dataclass(frozen=True)
|
29
|
+
class BaseTable(lang.Abstract):
|
30
|
+
id: int
|
31
|
+
|
32
|
+
created_at: datetime.datetime
|
33
|
+
updated_at: datetime.datetime
|
34
|
+
|
35
|
+
@td.tableclass('user')
|
36
|
+
@dc.dataclass(frozen=True)
|
37
|
+
class User(BaseTable, lang.Final):
|
38
|
+
name: str
|
39
|
+
|
40
|
+
"""
|
41
|
+
from ... import dataclasses as dc
|
42
|
+
from ... import lang
|
43
|
+
from .elements import Elements
|
44
|
+
|
45
|
+
|
46
|
+
##
|
47
|
+
|
48
|
+
|
49
|
+
@dc.dataclass(frozen=True)
|
50
|
+
class TableDef(lang.Final):
|
51
|
+
name: str
|
52
|
+
elements: Elements
|