""" Demo ID Transformer Utility Provides XOR-based ID transformation for creating unique but deterministic IDs across different demo tenants while maintaining cross-service consistency. This ensures that: 1. Same base ID + same tenant ID = same transformed ID (deterministic) 2. Different tenant IDs = different transformed IDs (isolation) 3. Cross-service relationships are preserved (consistency) """ import uuid from typing import Union def transform_id(base_id: Union[str, uuid.UUID], tenant_id: Union[str, uuid.UUID]) -> uuid.UUID: """ Transform a base ID using XOR with tenant ID to create unique but deterministic IDs. Args: base_id: Original UUID (string or UUID object) tenant_id: Tenant UUID (string or UUID object) Returns: Transformed UUID that is unique to this tenant but deterministic Example: >>> base_uuid = UUID('10000000-0000-0000-0000-000000000001') >>> tenant_uuid = UUID('a1b2c3d4-e5f6-47a8-b9c0-d1e2f3a4b5c6') >>> transform_id(base_uuid, tenant_uuid) # Returns deterministic UUID based on XOR of the two """ # Convert inputs to UUID objects if they aren't already if isinstance(base_id, str): base_uuid = uuid.UUID(base_id) else: base_uuid = base_id if isinstance(tenant_id, str): tenant_uuid = uuid.UUID(tenant_id) else: tenant_uuid = tenant_id # Convert UUIDs to 16-byte arrays base_bytes = base_uuid.bytes tenant_bytes = tenant_uuid.bytes # Apply XOR transformation transformed_bytes = bytes(b1 ^ b2 for b1, b2 in zip(base_bytes, tenant_bytes)) # Create new UUID from transformed bytes transformed_uuid = uuid.UUID(bytes=transformed_bytes) return transformed_uuid def generate_deterministic_uuid_from_string(input_string: str, tenant_id: Union[str, uuid.UUID]) -> uuid.UUID: """ Generate a deterministic UUID from a string input and tenant ID. Useful for transforming non-UUID identifiers (like SKUs) into UUIDs while maintaining determinism across services. Args: input_string: String identifier (e.g., SKU, product code) tenant_id: Tenant UUID for isolation Returns: Deterministic UUID based on the input string and tenant """ if isinstance(tenant_id, str): tenant_uuid = uuid.UUID(tenant_id) else: tenant_uuid = tenant_id # Create a combined string for hashing combined = f"{input_string}-{tenant_uuid}" # Use SHA-256 hash to create deterministic UUID import hashlib hash_obj = hashlib.sha256(combined.encode('utf-8')) # Use first 16 bytes for UUID v5 namespace hash_bytes = hash_obj.digest()[:16] # Create UUID v5 using a standard namespace namespace_uuid = uuid.NAMESPACE_DNS # Using DNS namespace as base deterministic_uuid = uuid.uuid5(namespace_uuid, combined) return deterministic_uuid # Utility functions for common transformations def transform_ingredient_id(base_ingredient_id: Union[str, uuid.UUID], tenant_id: Union[str, uuid.UUID]) -> uuid.UUID: """Transform an ingredient ID for a specific tenant""" return transform_id(base_ingredient_id, tenant_id) def transform_recipe_id(base_recipe_id: Union[str, uuid.UUID], tenant_id: Union[str, uuid.UUID]) -> uuid.UUID: """Transform a recipe ID for a specific tenant""" return transform_id(base_recipe_id, tenant_id) def transform_supplier_id(base_supplier_id: Union[str, uuid.UUID], tenant_id: Union[str, uuid.UUID]) -> uuid.UUID: """Transform a supplier ID for a specific tenant""" return transform_id(base_supplier_id, tenant_id) def transform_production_batch_id(base_batch_id: Union[str, uuid.UUID], tenant_id: Union[str, uuid.UUID]) -> uuid.UUID: """Transform a production batch ID for a specific tenant""" return transform_id(base_batch_id, tenant_id)