dominus-sdk-python-dev 2.1.6__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.
- dominus/__init__.py +47 -0
- dominus/config/__init__.py +24 -0
- dominus/config/endpoints.py +39 -0
- dominus/errors.py +201 -0
- dominus/helpers/__init__.py +2 -0
- dominus/helpers/auth.py +23 -0
- dominus/helpers/cache.py +192 -0
- dominus/helpers/core.py +657 -0
- dominus/helpers/crypto.py +118 -0
- dominus/namespaces/__init__.py +26 -0
- dominus/namespaces/_deprecated_crossover.py +10 -0
- dominus/namespaces/_deprecated_sql.py +1341 -0
- dominus/namespaces/auth.py +1056 -0
- dominus/namespaces/courier.py +251 -0
- dominus/namespaces/db.py +267 -0
- dominus/namespaces/ddl.py +590 -0
- dominus/namespaces/files.py +299 -0
- dominus/namespaces/health.py +59 -0
- dominus/namespaces/logs.py +367 -0
- dominus/namespaces/open.py +72 -0
- dominus/namespaces/portal.py +504 -0
- dominus/namespaces/redis.py +357 -0
- dominus/namespaces/secrets.py +126 -0
- dominus/services/__init__.py +2 -0
- dominus/services/_deprecated_architect.py +323 -0
- dominus/services/_deprecated_sovereign.py +93 -0
- dominus/start.py +1034 -0
- dominus_sdk_python_dev-2.1.6.dist-info/METADATA +381 -0
- dominus_sdk_python_dev-2.1.6.dist-info/RECORD +31 -0
- dominus_sdk_python_dev-2.1.6.dist-info/WHEEL +5 -0
- dominus_sdk_python_dev-2.1.6.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,590 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DDL Namespace - Smith schema and migration operations.
|
|
3
|
+
|
|
4
|
+
Provides DDL operations and Alembic migration management.
|
|
5
|
+
"""
|
|
6
|
+
from typing import Any, Dict, List, Optional, TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from ..start import Dominus
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class DdlNamespace:
|
|
13
|
+
"""
|
|
14
|
+
Schema DDL and migration namespace.
|
|
15
|
+
|
|
16
|
+
All DDL operations go through /api/smith/* endpoints.
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
# Table operations
|
|
20
|
+
await dominus.ddl.create_table("tenant_acme", "users", [
|
|
21
|
+
{"name": "id", "type": "UUID", "primary_key": True},
|
|
22
|
+
{"name": "email", "type": "VARCHAR(255)", "nullable": False}
|
|
23
|
+
])
|
|
24
|
+
|
|
25
|
+
# Column operations
|
|
26
|
+
await dominus.ddl.add_column("tenant_acme", "users", "phone", "VARCHAR(20)")
|
|
27
|
+
|
|
28
|
+
# Migrations
|
|
29
|
+
migrations = await dominus.ddl.list_migrations("tenant_acme")
|
|
30
|
+
|
|
31
|
+
# Provisioning
|
|
32
|
+
await dominus.ddl.provision_tenant("acme")
|
|
33
|
+
await dominus.ddl.provision_from_category("acme", "healthcare")
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, client: "Dominus"):
|
|
37
|
+
self._client = client
|
|
38
|
+
|
|
39
|
+
# ========================================
|
|
40
|
+
# SCHEMA DDL OPERATIONS
|
|
41
|
+
# ========================================
|
|
42
|
+
|
|
43
|
+
async def create_table(
|
|
44
|
+
self,
|
|
45
|
+
schema: str,
|
|
46
|
+
table: str,
|
|
47
|
+
columns: List[Dict[str, Any]]
|
|
48
|
+
) -> Dict[str, Any]:
|
|
49
|
+
"""
|
|
50
|
+
Create a new table.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
schema: Schema name (e.g., "tenant_acme")
|
|
54
|
+
table: Table name
|
|
55
|
+
columns: List of column definitions:
|
|
56
|
+
[{"name": "id", "type": "UUID", "primary_key": True}]
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Creation confirmation with migration_version
|
|
60
|
+
"""
|
|
61
|
+
return await self._client._request(
|
|
62
|
+
endpoint="/api/smith/schema/create-table",
|
|
63
|
+
body={
|
|
64
|
+
"schema": schema,
|
|
65
|
+
"table": table,
|
|
66
|
+
"columns": columns
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
async def drop_table(self, schema: str, table: str) -> Dict[str, Any]:
|
|
71
|
+
"""Drop a table."""
|
|
72
|
+
return await self._client._request(
|
|
73
|
+
endpoint="/api/smith/schema/drop-table",
|
|
74
|
+
method="DELETE",
|
|
75
|
+
body={"schema": schema, "table": table}
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
async def truncate_table(self, schema: str, table: str) -> Dict[str, Any]:
|
|
79
|
+
"""Truncate a table (delete all rows)."""
|
|
80
|
+
return await self._client._request(
|
|
81
|
+
endpoint="/api/smith/schema/truncate-table",
|
|
82
|
+
body={"schema": schema, "table": table}
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# ========================================
|
|
86
|
+
# COLUMN OPERATIONS
|
|
87
|
+
# ========================================
|
|
88
|
+
|
|
89
|
+
async def add_column(
|
|
90
|
+
self,
|
|
91
|
+
schema: str,
|
|
92
|
+
table: str,
|
|
93
|
+
column: str,
|
|
94
|
+
column_type: str,
|
|
95
|
+
nullable: bool = True,
|
|
96
|
+
default: Optional[str] = None
|
|
97
|
+
) -> Dict[str, Any]:
|
|
98
|
+
"""
|
|
99
|
+
Add a column to a table.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
schema: Schema name
|
|
103
|
+
table: Table name
|
|
104
|
+
column: Column name
|
|
105
|
+
column_type: PostgreSQL type (e.g., "VARCHAR(100)")
|
|
106
|
+
nullable: Allow NULL values (default: True)
|
|
107
|
+
default: Optional default value
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Alteration confirmation with migration_version
|
|
111
|
+
"""
|
|
112
|
+
body = {
|
|
113
|
+
"schema": schema,
|
|
114
|
+
"table": table,
|
|
115
|
+
"column": column,
|
|
116
|
+
"type": column_type,
|
|
117
|
+
"nullable": nullable
|
|
118
|
+
}
|
|
119
|
+
if default is not None:
|
|
120
|
+
body["default"] = default
|
|
121
|
+
|
|
122
|
+
return await self._client._request(
|
|
123
|
+
endpoint="/api/smith/schema/add-column",
|
|
124
|
+
body=body
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
async def drop_column(
|
|
128
|
+
self,
|
|
129
|
+
schema: str,
|
|
130
|
+
table: str,
|
|
131
|
+
column: str
|
|
132
|
+
) -> Dict[str, Any]:
|
|
133
|
+
"""Drop a column from a table."""
|
|
134
|
+
return await self._client._request(
|
|
135
|
+
endpoint="/api/smith/schema/drop-column",
|
|
136
|
+
method="DELETE",
|
|
137
|
+
body={
|
|
138
|
+
"schema": schema,
|
|
139
|
+
"table": table,
|
|
140
|
+
"column": column
|
|
141
|
+
}
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
async def alter_column(
|
|
145
|
+
self,
|
|
146
|
+
schema: str,
|
|
147
|
+
table: str,
|
|
148
|
+
column: str,
|
|
149
|
+
new_type: Optional[str] = None,
|
|
150
|
+
nullable: Optional[bool] = None,
|
|
151
|
+
default: Optional[str] = None
|
|
152
|
+
) -> Dict[str, Any]:
|
|
153
|
+
"""
|
|
154
|
+
Alter a column's properties.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
schema: Schema name
|
|
158
|
+
table: Table name
|
|
159
|
+
column: Column name
|
|
160
|
+
new_type: New column type
|
|
161
|
+
nullable: Set nullable status
|
|
162
|
+
default: New default value (use "DROP" to remove)
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
Alteration confirmation
|
|
166
|
+
"""
|
|
167
|
+
body = {
|
|
168
|
+
"schema": schema,
|
|
169
|
+
"table": table,
|
|
170
|
+
"column": column
|
|
171
|
+
}
|
|
172
|
+
if new_type:
|
|
173
|
+
body["type"] = new_type
|
|
174
|
+
if nullable is not None:
|
|
175
|
+
body["nullable"] = nullable
|
|
176
|
+
if default is not None:
|
|
177
|
+
body["default"] = default
|
|
178
|
+
|
|
179
|
+
return await self._client._request(
|
|
180
|
+
endpoint="/api/smith/schema/alter-column",
|
|
181
|
+
method="PUT",
|
|
182
|
+
body=body
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
async def rename_column(
|
|
186
|
+
self,
|
|
187
|
+
schema: str,
|
|
188
|
+
table: str,
|
|
189
|
+
old_name: str,
|
|
190
|
+
new_name: str
|
|
191
|
+
) -> Dict[str, Any]:
|
|
192
|
+
"""Rename a column."""
|
|
193
|
+
return await self._client._request(
|
|
194
|
+
endpoint="/api/smith/schema/rename-column",
|
|
195
|
+
body={
|
|
196
|
+
"schema": schema,
|
|
197
|
+
"table": table,
|
|
198
|
+
"old_name": old_name,
|
|
199
|
+
"new_name": new_name
|
|
200
|
+
}
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# ========================================
|
|
204
|
+
# INDEX OPERATIONS
|
|
205
|
+
# ========================================
|
|
206
|
+
|
|
207
|
+
async def create_index(
|
|
208
|
+
self,
|
|
209
|
+
schema: str,
|
|
210
|
+
table: str,
|
|
211
|
+
index_name: str,
|
|
212
|
+
columns: List[str],
|
|
213
|
+
unique: bool = False
|
|
214
|
+
) -> Dict[str, Any]:
|
|
215
|
+
"""Create an index on columns."""
|
|
216
|
+
return await self._client._request(
|
|
217
|
+
endpoint="/api/smith/schema/create-index",
|
|
218
|
+
body={
|
|
219
|
+
"schema": schema,
|
|
220
|
+
"table": table,
|
|
221
|
+
"index_name": index_name,
|
|
222
|
+
"columns": columns,
|
|
223
|
+
"unique": unique
|
|
224
|
+
}
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
async def drop_index(
|
|
228
|
+
self,
|
|
229
|
+
schema: str,
|
|
230
|
+
index_name: str
|
|
231
|
+
) -> Dict[str, Any]:
|
|
232
|
+
"""Drop an index."""
|
|
233
|
+
return await self._client._request(
|
|
234
|
+
endpoint="/api/smith/schema/drop-index",
|
|
235
|
+
method="DELETE",
|
|
236
|
+
body={"schema": schema, "index_name": index_name}
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
# ========================================
|
|
240
|
+
# CONSTRAINT OPERATIONS
|
|
241
|
+
# ========================================
|
|
242
|
+
|
|
243
|
+
async def add_constraint(
|
|
244
|
+
self,
|
|
245
|
+
schema: str,
|
|
246
|
+
table: str,
|
|
247
|
+
constraint_name: str,
|
|
248
|
+
constraint_type: str,
|
|
249
|
+
definition: str
|
|
250
|
+
) -> Dict[str, Any]:
|
|
251
|
+
"""Add a constraint to a table."""
|
|
252
|
+
return await self._client._request(
|
|
253
|
+
endpoint="/api/smith/schema/add-constraint",
|
|
254
|
+
body={
|
|
255
|
+
"schema": schema,
|
|
256
|
+
"table": table,
|
|
257
|
+
"constraint_name": constraint_name,
|
|
258
|
+
"constraint_type": constraint_type,
|
|
259
|
+
"definition": definition
|
|
260
|
+
}
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
async def drop_constraint(
|
|
264
|
+
self,
|
|
265
|
+
schema: str,
|
|
266
|
+
table: str,
|
|
267
|
+
constraint_name: str
|
|
268
|
+
) -> Dict[str, Any]:
|
|
269
|
+
"""Drop a constraint from a table."""
|
|
270
|
+
return await self._client._request(
|
|
271
|
+
endpoint="/api/smith/schema/drop-constraint",
|
|
272
|
+
method="DELETE",
|
|
273
|
+
body={
|
|
274
|
+
"schema": schema,
|
|
275
|
+
"table": table,
|
|
276
|
+
"constraint_name": constraint_name
|
|
277
|
+
}
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# ========================================
|
|
281
|
+
# RAW DDL (Admin Only)
|
|
282
|
+
# ========================================
|
|
283
|
+
|
|
284
|
+
async def execute_raw(self, schema: str, sql: str) -> Dict[str, Any]:
|
|
285
|
+
"""
|
|
286
|
+
Execute raw DDL SQL (admin only).
|
|
287
|
+
|
|
288
|
+
Use with caution - this bypasses safety checks.
|
|
289
|
+
SQL must be base64 encoded.
|
|
290
|
+
"""
|
|
291
|
+
import base64
|
|
292
|
+
sql_b64 = base64.b64encode(sql.encode('utf-8')).decode('utf-8')
|
|
293
|
+
|
|
294
|
+
return await self._client._request(
|
|
295
|
+
endpoint="/api/smith/schema/execute-raw-ddl",
|
|
296
|
+
body={"schema": schema, "sql": sql_b64}
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
# ========================================
|
|
300
|
+
# MIGRATIONS
|
|
301
|
+
# ========================================
|
|
302
|
+
|
|
303
|
+
async def list_migrations(self, schema: str) -> List[Dict[str, Any]]:
|
|
304
|
+
"""List migrations for a schema."""
|
|
305
|
+
result = await self._client._request(
|
|
306
|
+
endpoint=f"/api/smith/migrations/list/{schema}",
|
|
307
|
+
method="GET"
|
|
308
|
+
)
|
|
309
|
+
return result if isinstance(result, list) else []
|
|
310
|
+
|
|
311
|
+
async def get_current_version(self, schema: str) -> Dict[str, Any]:
|
|
312
|
+
"""Get current migration version for a schema."""
|
|
313
|
+
return await self._client._request(
|
|
314
|
+
endpoint=f"/api/smith/migrations/current/{schema}",
|
|
315
|
+
method="GET"
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
async def get_migration_file(self, schema: str, version: str) -> Dict[str, Any]:
|
|
319
|
+
"""Get a specific migration file content."""
|
|
320
|
+
return await self._client._request(
|
|
321
|
+
endpoint=f"/api/smith/migrations/file/{schema}/{version}",
|
|
322
|
+
method="GET"
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
async def migration_history(self, schema: str) -> Dict[str, Any]:
|
|
326
|
+
"""Get migration history for a schema."""
|
|
327
|
+
return await self._client._request(
|
|
328
|
+
endpoint=f"/api/smith/migrations/history/{schema}",
|
|
329
|
+
method="GET"
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
async def rollback_migration(self, schema: str, version: str) -> Dict[str, Any]:
|
|
333
|
+
"""Rollback to a previous migration version."""
|
|
334
|
+
return await self._client._request(
|
|
335
|
+
endpoint=f"/api/smith/migrations/rollback/{schema}",
|
|
336
|
+
body={"version": version}
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
async def compare_versions(self, schemas: List[str]) -> Dict[str, Any]:
|
|
340
|
+
"""Compare migration versions across multiple schemas."""
|
|
341
|
+
schemas_param = ",".join(schemas)
|
|
342
|
+
return await self._client._request(
|
|
343
|
+
endpoint=f"/api/smith/migrations/compare?schemas={schemas_param}",
|
|
344
|
+
method="GET"
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
# ========================================
|
|
348
|
+
# CATEGORY MIGRATIONS
|
|
349
|
+
# ========================================
|
|
350
|
+
|
|
351
|
+
async def list_category_migrations(self, category_slug: str) -> Dict[str, Any]:
|
|
352
|
+
"""List migrations for a tenant category."""
|
|
353
|
+
return await self._client._request(
|
|
354
|
+
endpoint=f"/api/smith/migrations/category/{category_slug}/list",
|
|
355
|
+
method="GET"
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
async def get_category_migration_file(
|
|
359
|
+
self,
|
|
360
|
+
category_slug: str,
|
|
361
|
+
version: str
|
|
362
|
+
) -> Dict[str, Any]:
|
|
363
|
+
"""Get a specific category migration file."""
|
|
364
|
+
return await self._client._request(
|
|
365
|
+
endpoint=f"/api/smith/migrations/category/{category_slug}/file/{version}",
|
|
366
|
+
method="GET"
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
async def category_sync_status(self, category_slug: str) -> Dict[str, Any]:
|
|
370
|
+
"""Get sync status for all tenants in a category."""
|
|
371
|
+
return await self._client._request(
|
|
372
|
+
endpoint=f"/api/smith/migrations/category/{category_slug}/sync-status",
|
|
373
|
+
method="GET"
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
async def list_public_migrations(self) -> Dict[str, Any]:
|
|
377
|
+
"""List migrations for the public schema."""
|
|
378
|
+
return await self._client._request(
|
|
379
|
+
endpoint="/api/smith/migrations/public/list",
|
|
380
|
+
method="GET"
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
# ========================================
|
|
384
|
+
# CATEGORY DDL (Atomic across tenants)
|
|
385
|
+
# ========================================
|
|
386
|
+
|
|
387
|
+
async def category_create_table(
|
|
388
|
+
self,
|
|
389
|
+
category_slug: str,
|
|
390
|
+
table: str,
|
|
391
|
+
columns: List[Dict[str, Any]],
|
|
392
|
+
target: str = "category"
|
|
393
|
+
) -> Dict[str, Any]:
|
|
394
|
+
"""
|
|
395
|
+
Create table in all tenant schemas of a category (atomic).
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
category_slug: Category identifier
|
|
399
|
+
table: Table name
|
|
400
|
+
columns: Column definitions
|
|
401
|
+
target: "category" or "public"
|
|
402
|
+
"""
|
|
403
|
+
return await self._client._request(
|
|
404
|
+
endpoint="/api/smith/category/create-table",
|
|
405
|
+
body={
|
|
406
|
+
"target": target,
|
|
407
|
+
"category_slug": category_slug,
|
|
408
|
+
"table": table,
|
|
409
|
+
"columns": columns
|
|
410
|
+
}
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
async def category_add_column(
|
|
414
|
+
self,
|
|
415
|
+
category_slug: str,
|
|
416
|
+
table: str,
|
|
417
|
+
column: str,
|
|
418
|
+
column_type: str,
|
|
419
|
+
nullable: bool = True,
|
|
420
|
+
target: str = "category"
|
|
421
|
+
) -> Dict[str, Any]:
|
|
422
|
+
"""Add column to all tenant schemas of a category (atomic)."""
|
|
423
|
+
return await self._client._request(
|
|
424
|
+
endpoint="/api/smith/category/add-column",
|
|
425
|
+
body={
|
|
426
|
+
"target": target,
|
|
427
|
+
"category_slug": category_slug,
|
|
428
|
+
"table": table,
|
|
429
|
+
"column": column,
|
|
430
|
+
"type": column_type,
|
|
431
|
+
"nullable": nullable
|
|
432
|
+
}
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
async def category_drop_table(
|
|
436
|
+
self,
|
|
437
|
+
category_slug: str,
|
|
438
|
+
table: str,
|
|
439
|
+
target: str = "category"
|
|
440
|
+
) -> Dict[str, Any]:
|
|
441
|
+
"""Drop table from all tenant schemas of a category (admin only)."""
|
|
442
|
+
return await self._client._request(
|
|
443
|
+
endpoint="/api/smith/category/drop-table",
|
|
444
|
+
method="DELETE",
|
|
445
|
+
body={
|
|
446
|
+
"target": target,
|
|
447
|
+
"category_slug": category_slug,
|
|
448
|
+
"table": table
|
|
449
|
+
}
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
async def category_drop_column(
|
|
453
|
+
self,
|
|
454
|
+
category_slug: str,
|
|
455
|
+
table: str,
|
|
456
|
+
column: str,
|
|
457
|
+
target: str = "category"
|
|
458
|
+
) -> Dict[str, Any]:
|
|
459
|
+
"""Drop column from all tenant schemas of a category (admin only)."""
|
|
460
|
+
return await self._client._request(
|
|
461
|
+
endpoint="/api/smith/category/drop-column",
|
|
462
|
+
method="DELETE",
|
|
463
|
+
body={
|
|
464
|
+
"target": target,
|
|
465
|
+
"category_slug": category_slug,
|
|
466
|
+
"table": table,
|
|
467
|
+
"column": column
|
|
468
|
+
}
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
async def category_create_index(
|
|
472
|
+
self,
|
|
473
|
+
category_slug: str,
|
|
474
|
+
table: str,
|
|
475
|
+
index_name: str,
|
|
476
|
+
columns: List[str],
|
|
477
|
+
unique: bool = False,
|
|
478
|
+
target: str = "category"
|
|
479
|
+
) -> Dict[str, Any]:
|
|
480
|
+
"""Create index in all tenant schemas of a category (atomic)."""
|
|
481
|
+
return await self._client._request(
|
|
482
|
+
endpoint="/api/smith/category/create-index",
|
|
483
|
+
body={
|
|
484
|
+
"target": target,
|
|
485
|
+
"category_slug": category_slug,
|
|
486
|
+
"table": table,
|
|
487
|
+
"index_name": index_name,
|
|
488
|
+
"columns": columns,
|
|
489
|
+
"unique": unique
|
|
490
|
+
}
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
# ========================================
|
|
494
|
+
# TENANT PROVISIONING
|
|
495
|
+
# ========================================
|
|
496
|
+
|
|
497
|
+
async def provision_tenant(self, tenant_slug: str) -> Dict[str, Any]:
|
|
498
|
+
"""
|
|
499
|
+
Provision a new tenant schema.
|
|
500
|
+
|
|
501
|
+
Creates: tenant_{slug} schema with proper permissions.
|
|
502
|
+
|
|
503
|
+
Args:
|
|
504
|
+
tenant_slug: Tenant identifier (becomes schema name: tenant_{slug})
|
|
505
|
+
|
|
506
|
+
Returns:
|
|
507
|
+
Provisioning result with schema name and initial version
|
|
508
|
+
"""
|
|
509
|
+
return await self._client._request(
|
|
510
|
+
endpoint="/api/smith/provision/tenant-schema",
|
|
511
|
+
body={"tenant_slug": tenant_slug}
|
|
512
|
+
)
|
|
513
|
+
|
|
514
|
+
async def deprovision_tenant(
|
|
515
|
+
self,
|
|
516
|
+
tenant_slug: str,
|
|
517
|
+
cascade: bool = False
|
|
518
|
+
) -> Dict[str, Any]:
|
|
519
|
+
"""
|
|
520
|
+
Drop a tenant schema (destructive).
|
|
521
|
+
|
|
522
|
+
Args:
|
|
523
|
+
tenant_slug: Tenant identifier
|
|
524
|
+
cascade: If True, drops all dependent objects
|
|
525
|
+
"""
|
|
526
|
+
return await self._client._request(
|
|
527
|
+
endpoint="/api/smith/provision/tenant-schema",
|
|
528
|
+
method="DELETE",
|
|
529
|
+
body={"tenant_slug": tenant_slug, "cascade": cascade}
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
async def provision_from_category(
|
|
533
|
+
self,
|
|
534
|
+
tenant_slug: str,
|
|
535
|
+
category_slug: str
|
|
536
|
+
) -> Dict[str, Any]:
|
|
537
|
+
"""
|
|
538
|
+
Provision tenant with category-specific migrations.
|
|
539
|
+
|
|
540
|
+
Args:
|
|
541
|
+
tenant_slug: Tenant identifier
|
|
542
|
+
category_slug: Category for migrations to inherit
|
|
543
|
+
|
|
544
|
+
Returns:
|
|
545
|
+
Provisioning result with applied migrations
|
|
546
|
+
"""
|
|
547
|
+
return await self._client._request(
|
|
548
|
+
endpoint="/api/smith/provision/tenant-from-category",
|
|
549
|
+
body={
|
|
550
|
+
"tenant_slug": tenant_slug,
|
|
551
|
+
"category_slug": category_slug
|
|
552
|
+
}
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
async def provision_status(self, tenant_slug: str) -> Dict[str, Any]:
|
|
556
|
+
"""Get provision status for a tenant."""
|
|
557
|
+
return await self._client._request(
|
|
558
|
+
endpoint=f"/api/smith/provision/status/{tenant_slug}",
|
|
559
|
+
method="GET"
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
async def list_provisions(self) -> List[Dict[str, Any]]:
|
|
563
|
+
"""List all provisioned tenant schemas."""
|
|
564
|
+
result = await self._client._request(
|
|
565
|
+
endpoint="/api/smith/provision/list",
|
|
566
|
+
method="GET"
|
|
567
|
+
)
|
|
568
|
+
return result if isinstance(result, list) else []
|
|
569
|
+
|
|
570
|
+
async def list_categories(self) -> List[Dict[str, Any]]:
|
|
571
|
+
"""List all tenant categories."""
|
|
572
|
+
result = await self._client._request(
|
|
573
|
+
endpoint="/api/smith/provision/categories",
|
|
574
|
+
method="GET"
|
|
575
|
+
)
|
|
576
|
+
return result if isinstance(result, list) else []
|
|
577
|
+
|
|
578
|
+
async def category_status(self, category_slug: str) -> Dict[str, Any]:
|
|
579
|
+
"""Get migration sync status for all tenants in a category."""
|
|
580
|
+
return await self._client._request(
|
|
581
|
+
endpoint=f"/api/smith/provision/category-status/{category_slug}",
|
|
582
|
+
method="GET"
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
async def tenants_by_category(self, category_slug: str) -> Dict[str, Any]:
|
|
586
|
+
"""List all tenants in a category."""
|
|
587
|
+
return await self._client._request(
|
|
588
|
+
endpoint=f"/api/smith/provision/tenants-by-category/{category_slug}",
|
|
589
|
+
method="GET"
|
|
590
|
+
)
|