omlish 0.0.0.dev70__py3-none-any.whl → 0.0.0.dev72__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.
- 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
|