tigrbl-orm 0.1.0.dev1__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.
- tigrbl_orm/orm/__init__.py +1 -0
- tigrbl_orm/orm/mixins/_RowBound.py +83 -0
- tigrbl_orm/orm/mixins/__init__.py +95 -0
- tigrbl_orm/orm/mixins/bootstrappable.py +113 -0
- tigrbl_orm/orm/mixins/bound.py +47 -0
- tigrbl_orm/orm/mixins/edges.py +40 -0
- tigrbl_orm/orm/mixins/fields.py +165 -0
- tigrbl_orm/orm/mixins/hierarchy.py +54 -0
- tigrbl_orm/orm/mixins/key_digest.py +44 -0
- tigrbl_orm/orm/mixins/lifecycle.py +115 -0
- tigrbl_orm/orm/mixins/locks.py +51 -0
- tigrbl_orm/orm/mixins/markers.py +16 -0
- tigrbl_orm/orm/mixins/operations.py +57 -0
- tigrbl_orm/orm/mixins/ownable.py +337 -0
- tigrbl_orm/orm/mixins/principals.py +98 -0
- tigrbl_orm/orm/mixins/tenant_bound.py +301 -0
- tigrbl_orm/orm/mixins/upsertable.py +118 -0
- tigrbl_orm/orm/mixins/utils.py +49 -0
- tigrbl_orm/orm/tables/__init__.py +73 -0
- tigrbl_orm/orm/tables/_base.py +7 -0
- tigrbl_orm/orm/tables/audit.py +56 -0
- tigrbl_orm/orm/tables/client.py +25 -0
- tigrbl_orm/orm/tables/group.py +29 -0
- tigrbl_orm/orm/tables/org.py +30 -0
- tigrbl_orm/orm/tables/rbac.py +76 -0
- tigrbl_orm/orm/tables/status.py +106 -0
- tigrbl_orm/orm/tables/tenant.py +22 -0
- tigrbl_orm/orm/tables/user.py +39 -0
- tigrbl_orm-0.1.0.dev1.dist-info/METADATA +56 -0
- tigrbl_orm-0.1.0.dev1.dist-info/RECORD +31 -0
- tigrbl_orm-0.1.0.dev1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from uuid import UUID
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from ...specs import IO, F, acol, S
|
|
5
|
+
from ..._spec.storage_spec import ForeignKeySpec
|
|
6
|
+
from ...types import Integer, String, PgUUID, Mapped
|
|
7
|
+
|
|
8
|
+
from . import TableBase
|
|
9
|
+
from ..mixins import (
|
|
10
|
+
GUIDPk,
|
|
11
|
+
TenantBound,
|
|
12
|
+
RelationEdge,
|
|
13
|
+
Timestamped,
|
|
14
|
+
MaskableEdge,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# ───────── RBAC core ──────────────────────────────────────────────────
|
|
19
|
+
class Role(TableBase, GUIDPk, Timestamped, TenantBound):
|
|
20
|
+
__tablename__ = "roles"
|
|
21
|
+
slug: Mapped[str] = acol(
|
|
22
|
+
storage=S(String, unique=True),
|
|
23
|
+
field=F(),
|
|
24
|
+
io=IO(),
|
|
25
|
+
)
|
|
26
|
+
global_mask: Mapped[int] = acol(
|
|
27
|
+
storage=S(Integer, default=0),
|
|
28
|
+
field=F(),
|
|
29
|
+
io=IO(),
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class RolePerm(TableBase, GUIDPk, Timestamped, TenantBound, RelationEdge, MaskableEdge):
|
|
34
|
+
__tablename__ = "role_perms"
|
|
35
|
+
role_id: Mapped[UUID] = acol(
|
|
36
|
+
storage=S(PgUUID, fk=ForeignKeySpec("roles.id")),
|
|
37
|
+
field=F(),
|
|
38
|
+
io=IO(),
|
|
39
|
+
)
|
|
40
|
+
target_table: Mapped[str] = acol(
|
|
41
|
+
storage=S(String),
|
|
42
|
+
field=F(),
|
|
43
|
+
io=IO(),
|
|
44
|
+
)
|
|
45
|
+
target_id: Mapped[str] = acol(
|
|
46
|
+
storage=S(String),
|
|
47
|
+
field=F(),
|
|
48
|
+
io=IO(),
|
|
49
|
+
) # row or sentinel
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class RoleGrant(TableBase, GUIDPk, Timestamped, TenantBound, RelationEdge):
|
|
53
|
+
__tablename__ = "role_grants"
|
|
54
|
+
principal_id: Mapped[UUID] = acol(
|
|
55
|
+
storage=S(PgUUID),
|
|
56
|
+
field=F(),
|
|
57
|
+
io=IO(),
|
|
58
|
+
) # FK to principal row
|
|
59
|
+
role_id: Mapped[UUID] = acol(
|
|
60
|
+
storage=S(PgUUID, fk=ForeignKeySpec("roles.id")),
|
|
61
|
+
field=F(),
|
|
62
|
+
io=IO(),
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
__all__ = ["Role", "RolePerm", "RoleGrant"]
|
|
67
|
+
|
|
68
|
+
for _name in list(globals()):
|
|
69
|
+
if _name not in __all__ and not _name.startswith("__"):
|
|
70
|
+
del globals()[_name]
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def __dir__():
|
|
74
|
+
"""Tighten ``dir()`` output for interactive sessions."""
|
|
75
|
+
|
|
76
|
+
return sorted(__all__)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""
|
|
2
|
+
StatusEnum table
|
|
3
|
+
----------------
|
|
4
|
+
Canonical store of workflow / lifecycle states.
|
|
5
|
+
|
|
6
|
+
• The `Status` enum below should always be the **only** source of truth for
|
|
7
|
+
allowed values. Every place in the codebase ‒ mix-ins, business logic,
|
|
8
|
+
RPC schemas, etc. ‒ should import it instead of hard-coding strings.
|
|
9
|
+
• Domain tables that need a status field should `ForeignKey` to
|
|
10
|
+
`status_enums.code` **or** just declare a `Column(SAEnum(Status, …))`
|
|
11
|
+
if the FK is unnecessary.
|
|
12
|
+
|
|
13
|
+
If you add/remove a state later, just edit the `Status` enum – the rest
|
|
14
|
+
keeps working.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from enum import StrEnum
|
|
20
|
+
|
|
21
|
+
from ...specs import acol, F, IO, S
|
|
22
|
+
from ...types import Integer, Mapped, SAEnum, String
|
|
23
|
+
|
|
24
|
+
from ._base import TableBase
|
|
25
|
+
from ..mixins import Timestamped # created_at / updated_at
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# ────────────────────────────────────────────────────────────────────────
|
|
29
|
+
# 1. In-memory application enum (single source of truth)
|
|
30
|
+
# ────────────────────────────────────────────────────────────────────────
|
|
31
|
+
class Status(StrEnum):
|
|
32
|
+
# queued / dispatching
|
|
33
|
+
QUEUED = "queued"
|
|
34
|
+
WAITING = "waiting"
|
|
35
|
+
INPUT_REQUIRED = "input_required"
|
|
36
|
+
AUTH_REQUIRED = "auth_required"
|
|
37
|
+
|
|
38
|
+
# approvals
|
|
39
|
+
APPROVED = "approved"
|
|
40
|
+
REJECTED = "rejected"
|
|
41
|
+
|
|
42
|
+
# execution lifecycle
|
|
43
|
+
DISPATCHED = "dispatched"
|
|
44
|
+
RUNNING = "running"
|
|
45
|
+
PAUSED = "paused"
|
|
46
|
+
|
|
47
|
+
# final states
|
|
48
|
+
SUCCESS = "success"
|
|
49
|
+
FAILED = "failed"
|
|
50
|
+
CANCELLED = "cancelled"
|
|
51
|
+
|
|
52
|
+
# (legacy / generic)
|
|
53
|
+
PENDING = "pending" # optional catch-all
|
|
54
|
+
ACTIVE = "active"
|
|
55
|
+
SUSPENDED = "suspended"
|
|
56
|
+
DISABLED = "disabled"
|
|
57
|
+
DELETED = "deleted"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# ────────────────────────────────────────────────────────────────────────
|
|
61
|
+
# 2. Persistent lookup table
|
|
62
|
+
# ────────────────────────────────────────────────────────────────────────
|
|
63
|
+
class StatusEnum(TableBase, Timestamped):
|
|
64
|
+
"""
|
|
65
|
+
id – surrogate PK (easy FK if needed elsewhere)
|
|
66
|
+
code – canonical string value from the Status enum
|
|
67
|
+
label – human-readable label (“Paused”, “Failed”, …)
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
__tablename__ = "status_enums"
|
|
71
|
+
|
|
72
|
+
id: Mapped[int] = acol(
|
|
73
|
+
storage=S(Integer, primary_key=True, autoincrement=True),
|
|
74
|
+
field=F(),
|
|
75
|
+
io=IO(out_verbs=("read", "list")),
|
|
76
|
+
)
|
|
77
|
+
code: Mapped[Status] = acol(
|
|
78
|
+
storage=S(
|
|
79
|
+
SAEnum(Status, name="status_code_enum"),
|
|
80
|
+
nullable=False,
|
|
81
|
+
unique=True,
|
|
82
|
+
),
|
|
83
|
+
field=F(py_type=Status),
|
|
84
|
+
io=IO(out_verbs=("read", "list")),
|
|
85
|
+
)
|
|
86
|
+
label: Mapped[str] = acol(
|
|
87
|
+
storage=S(String, nullable=False),
|
|
88
|
+
field=F(),
|
|
89
|
+
io=IO(out_verbs=("read", "list")),
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
def __repr__(self) -> str: # noqa: D401
|
|
93
|
+
return f"<StatusEnum {self.code}>"
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
__all__ = ["Status", "StatusEnum"]
|
|
97
|
+
|
|
98
|
+
for _name in list(globals()):
|
|
99
|
+
if _name not in __all__ and not _name.startswith("__"):
|
|
100
|
+
del globals()[_name]
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def __dir__():
|
|
104
|
+
"""Tighten ``dir()`` output for interactive sessions."""
|
|
105
|
+
|
|
106
|
+
return sorted(__all__)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Tenant model."""
|
|
2
|
+
|
|
3
|
+
from ._base import TableBase
|
|
4
|
+
from ..mixins import GUIDPk, Slugged, Timestamped
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Tenant(TableBase, GUIDPk, Slugged, Timestamped):
|
|
8
|
+
__tablename__ = "tenants"
|
|
9
|
+
__abstract__ = True
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
__all__ = ["Tenant"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
for _name in list(globals()):
|
|
16
|
+
if _name not in __all__ and not _name.startswith("__"):
|
|
17
|
+
del globals()[_name]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def __dir__():
|
|
21
|
+
"""Tighten ``dir()`` output for interactive sessions."""
|
|
22
|
+
return sorted(__all__)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""User model."""
|
|
2
|
+
|
|
3
|
+
from ._base import TableBase
|
|
4
|
+
from ..mixins import (
|
|
5
|
+
GUIDPk,
|
|
6
|
+
Timestamped,
|
|
7
|
+
TenantBound,
|
|
8
|
+
Principal,
|
|
9
|
+
AsyncCapable,
|
|
10
|
+
ActiveToggle,
|
|
11
|
+
)
|
|
12
|
+
from ...specs import IO, acol, F, S
|
|
13
|
+
from ...types import Mapped, String
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class User(
|
|
17
|
+
TableBase, GUIDPk, Timestamped, TenantBound, Principal, AsyncCapable, ActiveToggle
|
|
18
|
+
):
|
|
19
|
+
__tablename__ = "users"
|
|
20
|
+
__abstract__ = True
|
|
21
|
+
username: Mapped[str] = acol(
|
|
22
|
+
storage=S(String(32), nullable=False),
|
|
23
|
+
field=F(constraints={"max_length": 32}),
|
|
24
|
+
io=IO(),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
__all__ = ["User"]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
for _name in list(globals()):
|
|
32
|
+
if _name not in __all__ and not _name.startswith("__"):
|
|
33
|
+
del globals()[_name]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def __dir__():
|
|
37
|
+
"""Tighten ``dir()`` output for interactive sessions."""
|
|
38
|
+
|
|
39
|
+
return sorted(__all__)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tigrbl-orm
|
|
3
|
+
Version: 0.1.0.dev1
|
|
4
|
+
Summary: ORM tables and mixins for the Tigrbl framework.
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Keywords: tigrbl,orm,sqlalchemy,sdk,standards
|
|
7
|
+
Author: Jacob Stewart
|
|
8
|
+
Author-email: jacob@swarmauri.com
|
|
9
|
+
Requires-Python: >=3.10,<3.13
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Development Status :: 1 - Planning
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Requires-Dist: sqlalchemy (>=2.0)
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
# tigrbl-orm
|
|
24
|
+
|
|
25
|
+
    
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- Provides the `tigrbl_orm.orm` module as a standalone package.
|
|
30
|
+
- Includes reusable ORM mixins and table models for Tigrbl services.
|
|
31
|
+
- Supports Python 3.10 through 3.12.
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
### uv
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
uv add tigrbl-orm
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### pip
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install tigrbl-orm
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from tigrbl_orm.orm.tables.user import User
|
|
51
|
+
|
|
52
|
+
print(User.__tablename__)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Install this package alongside other Tigrbl components when you need SQLAlchemy-backed models.
|
|
56
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
tigrbl_orm/orm/__init__.py,sha256=oQVk8swfAop9oNNC-WVf0_OdAmXRf7EjqIQfW7w_fLA,61
|
|
2
|
+
tigrbl_orm/orm/mixins/_RowBound.py,sha256=a2B7USX8fx6-kyVnQdoEW3CZCKxAwC5jWCfR-enpkCg,3054
|
|
3
|
+
tigrbl_orm/orm/mixins/__init__.py,sha256=X1qWzDcr_wSNNOo7JJ_hpHGR_tO1HsqDF7vHh6N-xNs,1914
|
|
4
|
+
tigrbl_orm/orm/mixins/bootstrappable.py,sha256=cIk20fMSHP3vd3AQLhAlHTTD3ds5X4JLMMZY8f2L1CM,3834
|
|
5
|
+
tigrbl_orm/orm/mixins/bound.py,sha256=hkLafLQOKZXKsTozq3bBYzjegsR9hGlpK-Q_88XheZ0,1332
|
|
6
|
+
tigrbl_orm/orm/mixins/edges.py,sha256=cqTa-R3n3ordDt52gGj49pNnchJ8i8NJ0053HKuWQ58,854
|
|
7
|
+
tigrbl_orm/orm/mixins/fields.py,sha256=CfQqRD949s7819-4487fYsdWbHDAbL4JXYaZfMdOHYE,3657
|
|
8
|
+
tigrbl_orm/orm/mixins/hierarchy.py,sha256=GrNJk4FFqZWxX-PCkCgqMS8jeYs4mswgpEbQlaOArc0,1411
|
|
9
|
+
tigrbl_orm/orm/mixins/key_digest.py,sha256=TEw3Cqc8cFW1f1PqmV6RcC_MQd3-clVz1-bKhRxTDXc,1393
|
|
10
|
+
tigrbl_orm/orm/mixins/lifecycle.py,sha256=4DjEL5iOdm2SaSG2Aw8lSkGmGGLUONAHCku7UAO9sv0,2615
|
|
11
|
+
tigrbl_orm/orm/mixins/locks.py,sha256=NMUpPNC612GGdFLYOvgwXrGI27V-3VXt6Tw2bwnYhnc,1262
|
|
12
|
+
tigrbl_orm/orm/mixins/markers.py,sha256=oa4_csrgdiX3uHX_IgpShxyEkmUkexJdJIrz1qMB46E,210
|
|
13
|
+
tigrbl_orm/orm/mixins/operations.py,sha256=XDeoeF003b2GymFTzj5_olkgzrjrFYfOjPi3jQrYziQ,1835
|
|
14
|
+
tigrbl_orm/orm/mixins/ownable.py,sha256=2nF3WfgOK3THikiw9-wO1RchPM7bqc6etM-iM6pRRY4,11304
|
|
15
|
+
tigrbl_orm/orm/mixins/principals.py,sha256=JQo526b20BAmeSJs4O1MNqJpj1dpRG_KHE1nhUj7DUw,2746
|
|
16
|
+
tigrbl_orm/orm/mixins/tenant_bound.py,sha256=ghorDEpBQvlb1agT7ilwGOeGSo6j0Ozi8dSN5dLStJQ,10095
|
|
17
|
+
tigrbl_orm/orm/mixins/upsertable.py,sha256=J854OHuoKXzmLGA5fPsMaKB4Zctl6wjJtJZ5WUqIc6w,3996
|
|
18
|
+
tigrbl_orm/orm/mixins/utils.py,sha256=_sTN4CnEkyEeXgTRr_VHsFtG33Mimm1EFoFhpPutGQo,1257
|
|
19
|
+
tigrbl_orm/orm/tables/__init__.py,sha256=OtKDm6V5je8DJ6M-9Xq_rZUSBm0l5fpFo9JKO6a1Boo,1972
|
|
20
|
+
tigrbl_orm/orm/tables/_base.py,sha256=vg9lsd-BgHitAthPpvia4yLy3GuuXzBTsMCoLPtMydA,150
|
|
21
|
+
tigrbl_orm/orm/tables/audit.py,sha256=UZsRWAGDx7PMvCjwL_nte4Ig50Oh-loCsoRPA_-VzNg,1426
|
|
22
|
+
tigrbl_orm/orm/tables/client.py,sha256=XW78zJwjjjQYWsaBuHR6iVZhuQaLYj97d3exhBXL75I,771
|
|
23
|
+
tigrbl_orm/orm/tables/group.py,sha256=TleC0a_TgQ_MxQzxyqQFvF91igdtK4rYB112ysWlBJU,634
|
|
24
|
+
tigrbl_orm/orm/tables/org.py,sha256=lMinui-4RHOraRPqCWRzKUUpSu82tEByF-GXhgl8g5g,650
|
|
25
|
+
tigrbl_orm/orm/tables/rbac.py,sha256=u5riD-ply0zmlZAtCCsPZ-rM1rTIMnCHC-tOBWPhFnk,1939
|
|
26
|
+
tigrbl_orm/orm/tables/status.py,sha256=1K120kuUDGXUQgyiEF4fu7Od9x_d40hrpUxw6h7tnqY,3588
|
|
27
|
+
tigrbl_orm/orm/tables/tenant.py,sha256=yTDrGktHqp7EE3dtE959SAqKOY6guNUbt-H__FQvmIM,460
|
|
28
|
+
tigrbl_orm/orm/tables/user.py,sha256=H5gWJXRbEkPxHb4-ZpfqT9DWKRzmx1njoeolK6ESQio,799
|
|
29
|
+
tigrbl_orm-0.1.0.dev1.dist-info/METADATA,sha256=EHBzZY7JJrEt792tgeOGNQgKQcRJsvC7Ovt1F9clX34,1715
|
|
30
|
+
tigrbl_orm-0.1.0.dev1.dist-info/WHEEL,sha256=kJCRJT_g0adfAJzTx2GUMmS80rTJIVHRCfG0DQgLq3o,88
|
|
31
|
+
tigrbl_orm-0.1.0.dev1.dist-info/RECORD,,
|