-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path22_namespaces.py
More file actions
115 lines (86 loc) · 3.68 KB
/
22_namespaces.py
File metadata and controls
115 lines (86 loc) · 3.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env python3
"""
SochDB Python SDK - Example: Multi-Tenant Namespaces (Embedded FFI)
Namespaces provide data isolation between tenants, applications,
or environments in a single database instance.
No server required - uses embedded FFI.
"""
import json
import shutil
from sochdb import Database
def main():
print("=" * 60)
print("SochDB - Multi-Tenant Namespace Example (Embedded FFI)")
print("=" * 60)
print("Note: This uses embedded Database - no server required!\n")
# Open embedded database
db = Database.open("./example_namespace_db")
print("--- Simulating Namespaces with Key Prefixes ---")
# In embedded mode, namespaces are simulated with key prefixes
# Format: ns:{namespace}:key
tenants = ["tenant_acme", "tenant_globex", "staging"]
for tenant in tenants:
print(f"✓ Created namespace: {tenant}")
print("\n--- Isolated Data Operations ---")
# Store data in each "namespace" (prefix)
def put_namespaced(tenant: str, key: str, value: bytes):
full_key = f"ns:{tenant}:{key}".encode()
db.put(full_key, value)
def get_namespaced(tenant: str, key: str) -> bytes:
full_key = f"ns:{tenant}:{key}".encode()
return db.get(full_key)
# Store config in tenant_acme
put_namespaced("tenant_acme", "config:api_key", b"acme-secret-123")
put_namespaced("tenant_acme", "config:max_users", b"1000")
put_namespaced("tenant_acme", "config:plan", b"enterprise")
print("✓ Stored config in tenant_acme")
# Store config in tenant_globex
put_namespaced("tenant_globex", "config:api_key", b"globex-secret-456")
put_namespaced("tenant_globex", "config:max_users", b"50")
put_namespaced("tenant_globex", "config:plan", b"startup")
print("✓ Stored config in tenant_globex")
print("\n--- Data Isolation Verification ---")
# Each tenant sees only their own data
acme_key = get_namespaced("tenant_acme", "config:api_key")
globex_key = get_namespaced("tenant_globex", "config:api_key")
print(f"tenant_acme API key: {acme_key.decode()}")
print(f"tenant_globex API key: {globex_key.decode()}")
# Cross-namespace access returns None
wrong_key = get_namespaced("tenant_acme", "config:wrong")
print(f"Non-existent key: {wrong_key}")
print("\n--- Scanning a Namespace ---")
# List all keys in tenant_acme namespace
prefix = b"ns:tenant_acme:"
print(f"Keys in tenant_acme:")
for key, value in db.scan_prefix(prefix):
# Strip the prefix for display
short_key = key.decode().replace("ns:tenant_acme:", "")
print(f" {short_key} = {value.decode()}")
print("\n--- Atomic Multi-Tenant Update ---")
# Atomically update configs across namespaces
with db.transaction() as txn:
# Update tenant_acme
txn.put(b"ns:tenant_acme:config:last_update", b"2026-01-07")
# Update tenant_globex
txn.put(b"ns:tenant_globex:config:last_update", b"2026-01-07")
# Both updates are atomic
print("✓ Atomically updated both tenants")
print("\n--- Namespace Patterns ---")
print("""
Key Format: ns:{namespace}:{key}
Examples:
- ns:prod:users:alice:email
- ns:staging:users:alice:email
- ns:tenant_123:orders:ord_456
Benefits:
- Zero data leakage between tenants
- Single database instance
- Easy to backup/restore per tenant
- scan_prefix() for efficient per-tenant queries
""")
# Cleanup
db.close()
shutil.rmtree("./example_namespace_db", ignore_errors=True)
print("✅ Namespace example complete!")
if __name__ == "__main__":
main()