vention-storage 0.1.0__py3-none-any.whl → 0.5.2__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.
storage/utils.py ADDED
@@ -0,0 +1,20 @@
1
+ from datetime import datetime, timezone, date, time
2
+ from typing import Literal, TypeVar, Any
3
+ from sqlmodel import SQLModel
4
+
5
+ ModelType = TypeVar("ModelType", bound=SQLModel)
6
+ Operation = Literal["create", "update", "delete", "soft_delete", "restore"]
7
+
8
+
9
+ def utcnow() -> datetime:
10
+ return datetime.now(timezone.utc)
11
+
12
+
13
+ def to_primitive(value: Any) -> Any:
14
+ """
15
+ Convert Python values to CSV/JSON-friendly scalars.
16
+ Datetime/date/time -> ISO 8601 strings; others unchanged.
17
+ """
18
+ if isinstance(value, (datetime, date, time)):
19
+ return value.isoformat()
20
+ return value
@@ -0,0 +1,318 @@
1
+ Metadata-Version: 2.1
2
+ Name: vention-storage
3
+ Version: 0.5.2
4
+ Summary: A framework for storing and managing component and application data for machine apps.
5
+ License: Proprietary
6
+ Author: VentionCo
7
+ Requires-Python: >=3.10,<3.11
8
+ Classifier: License :: Other/Proprietary License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Requires-Dist: fastapi (==0.121.1)
12
+ Requires-Dist: python-multipart (>=0.0.20,<0.0.21)
13
+ Requires-Dist: sqlmodel (==0.0.27)
14
+ Requires-Dist: uvicorn (>=0.35.0,<0.36.0)
15
+ Description-Content-Type: text/markdown
16
+
17
+ # Vention Storage
18
+
19
+ A framework for storing and managing component and application data with persistence, validation, and audit trails for machine applications.
20
+
21
+ ## Table of Contents
22
+
23
+ - [✨ Features](#-features)
24
+ - [🧠 Concepts & Overview](#-concepts--overview)
25
+ - [⚙️ Installation & Setup](#️-installation--setup)
26
+ - [🚀 Quickstart Tutorial](#-quickstart-tutorial)
27
+ - [🛠 How-to Guides](#-how-to-guides)
28
+ - [📖 API Reference](#-api-reference)
29
+ - [🔍 Troubleshooting & FAQ](#-troubleshooting--faq)
30
+
31
+ ## ✨ Features
32
+
33
+ - Persistent storage with SQLite
34
+ - Automatic audit trails (who, when, what changed)
35
+ - Strong typing & validation via SQLModel
36
+ - Lifecycle hooks before/after insert, update, delete
37
+ - Soft delete with `deleted_at` fields
38
+ - REST API generation with Create, Read, Update, Delete + audit
39
+ - Health & monitoring endpoints (audit log, schema diagram)
40
+ - Batch operations for insert/delete
41
+ - Session management with smart reuse & transactions
42
+ - Bootstrap system for one-command setup
43
+ - CSV export/import for backups and migration
44
+ - Database backup/restore with integrity checking
45
+
46
+ ## 🧠 Concepts & Overview
47
+
48
+ Vention Storage is a component-based persistence layer for machine apps:
49
+
50
+ - **Database** → SQLite database with managed sessions and transactions
51
+ - **ModelAccessor** → Strongly-typed Create, Read, Update, Delete interface for your SQLModel classes
52
+ - **Hooks** → Functions that run before/after Create, Read, Update, Delete operations
53
+ - **AuditLog** → Automatically records all data mutations
54
+ - **Routers** → Auto-generated FastAPI endpoints for Create, Read, Update, Delete + database management
55
+
56
+ ## ⚙️ Installation & Setup
57
+
58
+ ```bash
59
+ pip install vention-storage
60
+ ```
61
+
62
+ **Optional dependencies:**
63
+ - sqlalchemy-schemadisplay and Graphviz → enable database schema visualization
64
+
65
+ MacOS:
66
+ ```bash
67
+ brew install graphviz
68
+ pip install sqlalchemy-schemadisplay
69
+ ```
70
+
71
+ Linux (Debian/Ubuntu)
72
+ ```bash
73
+ sudo apt-get install graphviz
74
+ pip install sqlalchemy-schemadisplay
75
+ ```
76
+
77
+ ## 🚀 Quickstart Tutorial
78
+
79
+ Define a model, bootstrap storage, and get full Create, Read, Update, Delete endpoints in minutes:
80
+
81
+ ```python
82
+ from datetime import datetime
83
+ from typing import Optional
84
+ from sqlmodel import Field, SQLModel
85
+ from fastapi import FastAPI
86
+ from storage.bootstrap import bootstrap
87
+ from storage.accessor import ModelAccessor
88
+
89
+ class User(SQLModel, table=True):
90
+ id: Optional[int] = Field(default=None, primary_key=True)
91
+ name: str
92
+ email: str
93
+ deleted_at: Optional[datetime] = Field(default=None, index=True)
94
+
95
+ app = FastAPI()
96
+ user_accessor = ModelAccessor(User, "users")
97
+
98
+ bootstrap(
99
+ app,
100
+ accessors=[user_accessor],
101
+ database_url="sqlite:///./my_app.db",
102
+ create_tables=True
103
+ )
104
+ ```
105
+
106
+ ➡️ You now have Create, Read, Update, Delete, audit, backup, and CSV endpoints at `/users` and `/db`.
107
+
108
+ ## 🛠 How-to Guides
109
+
110
+ ### Bootstrap Multiple Models
111
+
112
+ ```python
113
+ # user_accessor was created earlier in the Quickstart example
114
+ # Reuse it here to bootstrap multiple models at once
115
+
116
+ product_accessor = ModelAccessor(Product, "products")
117
+
118
+ bootstrap(
119
+ app,
120
+ accessors=[user_accessor, product_accessor],
121
+ database_url="sqlite:///./my_app.db",
122
+ create_tables=True,
123
+ max_records_per_model=100,
124
+ enable_db_router=True
125
+ )
126
+ ```
127
+
128
+ ### Export to CSV
129
+
130
+ ```python
131
+ response = requests.get("http://localhost:8000/db/export.zip")
132
+ with open("backup.zip", "wb") as f:
133
+ f.write(response.content)
134
+ ```
135
+
136
+ ### Backup & Restore
137
+
138
+ ```python
139
+ # Backup
140
+ r = requests.get("http://localhost:8000/db/backup.sqlite")
141
+ with open("backup.sqlite", "wb") as f: f.write(r.content)
142
+
143
+ # Restore
144
+ with open("backup.sqlite", "rb") as f:
145
+ files = {"file": ("backup.sqlite", f, "application/x-sqlite3")}
146
+ requests.post("http://localhost:8000/db/restore", files=files)
147
+ ```
148
+
149
+ ### Use Lifecycle Hooks
150
+
151
+ ```python
152
+ @user_accessor.before_insert()
153
+ def validate_email(session, instance):
154
+ if "@" not in instance.email:
155
+ raise ValueError("Invalid email")
156
+
157
+ @user_accessor.after_insert()
158
+ def log_creation(session, instance):
159
+ print(f"User created: {instance.name}")
160
+ ```
161
+
162
+ ### Query Audit Logs
163
+
164
+ ```python
165
+ from storage.auditor import AuditLog
166
+ from sqlmodel import select
167
+
168
+ with database.transaction() as session:
169
+ logs = session.exec(select(AuditLog).where(AuditLog.component == "users")).all()
170
+ ```
171
+
172
+ ### Using the model accessors
173
+
174
+ ```python
175
+ # Create
176
+ user = user_accessor.insert(User(name="Alice", email="alice@example.com"), actor="admin")
177
+
178
+ # Read
179
+ user = user_accessor.get(user.id)
180
+
181
+ # Update
182
+ user.name = "Alice Smith"
183
+ user_accessor.save(user, actor="admin")
184
+
185
+ # Delete
186
+ user_accessor.delete(user.id, actor="admin")
187
+
188
+ # Restore (for soft-deleted models)
189
+ user_accessor.restore(user.id, actor="admin")
190
+ ```
191
+
192
+
193
+ ### Using the REST API
194
+
195
+ Once bootstrapped, each `ModelAccessor` automatically exposes full CRUD endpoints.
196
+
197
+ Example: interacting with the `/users` API.
198
+
199
+ ```typescript
200
+ import axios from "axios";
201
+
202
+ const api = axios.create({
203
+ baseURL: "http://localhost:8000", // your backend url
204
+ headers: { "X-User": "operator" }, // used in audit logs
205
+ });
206
+
207
+ // Create
208
+ export async function createUser(name: string, email: string) {
209
+ const res = await api.post("/users/", { name, email });
210
+ return res.data;
211
+ }
212
+
213
+ // Read
214
+ export async function getUser(id: number) {
215
+ const res = await api.get(`/users/${id}`);
216
+ return res.data;
217
+ }
218
+
219
+ // Update
220
+ export async function updateUser(id: number, name: string) {
221
+ const res = await api.put(`/users/${id}`, { name });
222
+ return res.data;
223
+ }
224
+
225
+ // Delete (soft delete if model supports deleted_at)
226
+ export async function deleteUser(id: number) {
227
+ await api.delete(`/users/${id}`);
228
+ }
229
+
230
+ // Restore
231
+ export async function restoreUser(id: number) {
232
+ await api.post(`/users/${id}/restore`);
233
+ }
234
+
235
+ // List
236
+ export async function listUsers() {
237
+ const res = await api.get("/users/");
238
+ return res.data;
239
+ }
240
+ ```
241
+
242
+
243
+ ## 📖 API Reference
244
+
245
+ ### bootstrap
246
+
247
+ ```python
248
+ def bootstrap(
249
+ app: FastAPI,
250
+ *,
251
+ accessors: Iterable[ModelAccessor[Any]],
252
+ database_url: Optional[str] = None,
253
+ create_tables: bool = True,
254
+ max_records_per_model: Optional[int] = 5,
255
+ enable_db_router: bool = True,
256
+ ) -> None
257
+ ```
258
+
259
+ ### ModelAccessor
260
+
261
+ ```python
262
+ ModelAccessor(model: Type[ModelType], component_name: str)
263
+ ```
264
+
265
+ **Read**
266
+ - `get(id, include_deleted=False) -> Optional[ModelType]`
267
+ - `all(include_deleted=False) -> List[ModelType]`
268
+
269
+ **Write**
270
+ - `insert(obj, actor="internal") -> ModelType`
271
+ - `save(obj, actor="internal") -> ModelType`
272
+ - `delete(id, actor="internal") -> bool`
273
+ - `restore(id, actor="internal") -> bool`
274
+
275
+ **Batch**
276
+ - `insert_many(objs, actor="internal") -> List[ModelType]`
277
+ - `delete_many(ids, actor="internal") -> int`
278
+
279
+ **Hooks**
280
+ - `@accessor.before_insert()`
281
+ - `@accessor.after_insert()`
282
+ - `@accessor.before_update()`
283
+ - `@accessor.after_update()`
284
+ - `@accessor.before_delete()`
285
+ - `@accessor.after_delete()`
286
+
287
+ ### Routers
288
+
289
+ - `build_crud_router(accessor, max_records=100) -> APIRouter`
290
+ - `build_db_router(audit_default_limit=100, audit_max_limit=1000) -> APIRouter`
291
+
292
+ ### Database Helpers
293
+
294
+ - `database.set_database_url(url: str) -> None`
295
+ - `database.get_engine() -> Engine`
296
+ - `database.transaction() -> Iterator[Session]`
297
+ - `database.use_session(session: Optional[Session] = None) -> Iterator[Session]`
298
+
299
+ ### AuditLog model
300
+
301
+ ```python
302
+ class AuditLog(SQLModel, table=True):
303
+ id: int
304
+ timestamp: datetime
305
+ component: str
306
+ record_id: int
307
+ operation: str
308
+ actor: str
309
+ before: Optional[Dict[str, Any]]
310
+ after: Optional[Dict[str, Any]]
311
+ ```
312
+
313
+ ## 🔍 Troubleshooting & FAQ
314
+
315
+ - **Diagram endpoint fails** → Ensure Graphviz + sqlalchemy-schemadisplay are installed.
316
+ - **No audit actor shown** → Provide X-User header in API requests.
317
+ - **Soft delete not working** → Your model must have a `deleted_at` field.
318
+ - **Restore fails** → Ensure `integrity_check=True` passes when restoring backups.
@@ -0,0 +1,13 @@
1
+ storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ storage/accessor.py,sha256=hpWenJQlQWNFppubC47lwG-j1ulyDlQlFJu06SufOtk,10385
3
+ storage/auditor.py,sha256=tsvsb9qlHdcknY5OAXRZBMcN4nFDKtN3Ln1LfgozJrw,2090
4
+ storage/bootstrap.py,sha256=16wbX5WIJd8atWYi2scvsIYjE7A-YDzfWzDp4sPZ17I,1444
5
+ storage/database.py,sha256=BGRnlH0qBVnYffp0F1TCWGb6OS8cdlMmEJ1-LeHH4oc,3184
6
+ storage/hooks.py,sha256=rMK8R-VO0B7caZn9HtTlcetx0KQMvsl1Aq-t9mbFA4Q,1298
7
+ storage/io_helpers.py,sha256=c9Lzqc1kKwMquleCriGHYIIWVgDUmJRakIB1TNMpOjs,5061
8
+ storage/router_database.py,sha256=UcsU_OBXVynNAGW6cHYdHvFdmfTtzBcO6x28mXlbsR4,10177
9
+ storage/router_model.py,sha256=uLxnn1zzeWTorEOEH5ExEsc3lHWCxjZwROSWaYbOXuU,8316
10
+ storage/utils.py,sha256=uK30rKwwb1lqxfP3qQzsqH53umW-dCLh1jOec1r2p1k,588
11
+ vention_storage-0.5.2.dist-info/METADATA,sha256=tKT0T0C5OuPa1dCbxj6G7TqzJYHkGWtYBV3dLkaXmZo,8396
12
+ vention_storage-0.5.2.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
13
+ vention_storage-0.5.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: poetry-core 1.9.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,17 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: vention-storage
3
- Version: 0.1.0
4
- Summary: A framework for storing and managing component and application data for machine apps.
5
- License: Proprietary
6
- Author: VentionCo
7
- Requires-Python: >=3.9,<3.11
8
- Classifier: License :: Other/Proprietary License
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.9
11
- Classifier: Programming Language :: Python :: 3.10
12
- Requires-Dist: fastapi (>=0.116.1,<0.117.0)
13
- Requires-Dist: sqlmodel (>=0.0.24,<0.0.25)
14
- Requires-Dist: uvicorn (>=0.35.0,<0.36.0)
15
- Description-Content-Type: text/markdown
16
-
17
-
@@ -1,4 +0,0 @@
1
- storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- vention_storage-0.1.0.dist-info/METADATA,sha256=_bHetbJV624TMALJNFAv6YT4YPfqZGe1HoE9mGaIipk,591
3
- vention_storage-0.1.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
4
- vention_storage-0.1.0.dist-info/RECORD,,