Source code for pqg.schema

import json
import typing as t
from collections.abc import Mapping
from dataclasses import dataclass, field

from .entity import Entity


[docs] @dataclass class Schema(Mapping): """ A dictionary-like class representing a database schema containing multiple entities. The Schema class provides dictionary-style access to Entity objects, allowing for both iteration over entities and direct access to specific entities by name. Attributes: entities (t.Set[Entity]): Set of Entity objects in the schema. _entity_map (t.Dict[str, Entity]): Internal mapping of entity names to Entity objects. """ entities: t.Set[Entity] = field(default_factory=set) _entity_map: t.Dict[str, Entity] = field(init=False) def __post_init__(self): """Initialize the internal entity mapping after entity set is created.""" self._entity_map = {entity.name: entity for entity in self.entities}
[docs] def __getitem__(self, key: str) -> Entity: """ Get an entity by name using dictionary-style access. Args: key (str): The name of the entity to retrieve. Returns: Entity: The requested entity. Raises: KeyError: If no entity exists with the given name. """ return self._entity_map[key]
[docs] def __iter__(self) -> t.Iterator[Entity]: """ Iterate over all entities in the schema. Returns: Iterator[Entity]: Iterator yielding Entity objects. """ return iter(self.entities)
[docs] def __len__(self) -> int: """ Get the number of entities in the schema. Returns: int: Total number of entities. """ return len(self.entities)
[docs] @staticmethod def from_dict(data: dict) -> 'Schema': """ Create a Schema instance from a dictionary. Similar to from_file but accepts a dictionary directly instead of reading from a file. This is useful for creating schemas programmatically or when the schema definition is already in memory. Args: data (dict): Dictionary containing the schema configuration. Expected to have an 'entities' key mapping to entity configs. Returns: Schema: A new Schema instance containing the entities defined in the dictionary. Raises: ValueError: If the dictionary structure is invalid. Example: schema_dict = { "entities": { "customer": { "primary_key": "id", "properties": {...}, "foreign_keys": {...} } } } schema = Schema.from_dict(schema_dict) """ if 'entities' not in data: return Schema(entities=set()) if not isinstance(data['entities'], dict): raise ValueError("'entities' must be a dictionary") try: return Schema( set( Entity.from_configuration(name, configuration) for name, configuration in data['entities'].items() ) ) except Exception as e: raise ValueError(f'Invalid schema configuration: {str(e)}') from e
[docs] @staticmethod def from_file(path: str) -> 'Schema': """ Create a Schema instance by loading entity configurations from a JSON file. This method reads a JSON file containing entity configurations and creates a Schema object with Entity instances for each configured entity. Args: path (str): The file path to the JSON configuration file. Returns: Schema: A new Schema instance containing the entities defined in the file. Raises: json.JSONDecodeError: If the file contains invalid JSON. FileNotFoundError: If the specified file does not exist. PermissionError: If the file cannot be read due to permission issues. Note: If the 'entities' key is not present in the JSON file, an empty Schema will be returned. Example: schema = Schema.from_file('path/to/schema_config.json') """ try: with open(path, 'r') as file: content = json.load(file) except json.JSONDecodeError as e: raise ValueError(f'Invalid JSON in file {path}: {str(e)}') from e except (FileNotFoundError, PermissionError) as e: raise IOError(f'Error reading file {path}: {str(e)}') from e if 'entities' not in content: return Schema(entities=set()) entities = set( Entity.from_configuration(name, configuration) for name, configuration in content['entities'].items() ) return Schema(entities)