···
2
+
Lexicon JSON to Data Model Converter
4
+
Provides bidirectional conversion between Lexicon JSON schemas and Python data models.
7
+
from typing import Any, Dict, Type, Union, TypeVar
8
+
from pydantic import BaseModel
9
+
from .exceptions import ValidationError, SerializationError
10
+
from .types.primitive import NullModel, BooleanModel, IntegerModel
11
+
from .types.string import StringModel
12
+
from .types.complex import ArrayModel, ObjectModel, ParamsModel
13
+
from .types.reference import TokenModel, RefModel, UnionModel
14
+
from .types.special import (
15
+
UnknownModel, RecordModel, QueryModel,
16
+
ProcedureModel, SubscriptionModel
19
+
class LexiconConverter:
21
+
Bidirectional converter between Lexicon JSON and Python data models.
24
+
modelMap (Dict[str, Type[BaseModel]]): Mapping from Lexicon types to model classes
30
+
"boolean": BooleanModel,
31
+
"integer": IntegerModel,
32
+
"string": StringModel,
35
+
"array": ArrayModel,
36
+
"object": ObjectModel,
37
+
"params": ParamsModel,
40
+
"token": TokenModel,
42
+
"union": UnionModel,
45
+
"unknown": UnknownModel,
46
+
"record": RecordModel,
47
+
"query": QueryModel,
48
+
"procedure": ProcedureModel,
49
+
"subscription": SubscriptionModel,
53
+
def fromLexicon(cls, lexiconJson: Union[str, Dict[str, Any]]) -> BaseModel:
55
+
Convert Lexicon JSON to Python data model instance.
58
+
lexiconJson: Lexicon JSON string or dict
61
+
Instance of appropriate Pydantic model
64
+
ValidationError: If JSON is invalid or doesn't match schema
65
+
SerializationError: If conversion fails
67
+
if isinstance(lexiconJson, str):
69
+
data = json.loads(lexiconJson)
70
+
except json.JSONDecodeError as e:
71
+
raise ValidationError("lexiconJson", f"Invalid JSON: {e}")
75
+
if not isinstance(data, dict):
76
+
raise ValidationError("lexiconJson", "Lexicon must be a JSON object")
78
+
if "type" not in data:
79
+
raise ValidationError("type", "Lexicon definition must have 'type' field")
81
+
typeName = data["type"]
82
+
if typeName not in cls.modelMap:
83
+
raise ValidationError("type", f"Unknown Lexicon type: {typeName}")
86
+
modelClass = cls.modelMap[typeName]
87
+
return modelClass(**data)
88
+
except Exception as e:
89
+
raise SerializationError(typeName, f"Failed to create model: {e}")
92
+
def toLexicon(cls, modelInstance: BaseModel) -> Dict[str, Any]:
94
+
Convert Python model instance back to Lexicon JSON format.
97
+
modelInstance: Instance of a Lexicon model
100
+
Dictionary representing Lexicon JSON
103
+
SerializationError: If conversion fails
105
+
if not isinstance(modelInstance, BaseModel):
106
+
raise SerializationError("modelInstance", "Input must be a Pydantic model")
109
+
# Get the model's type name by reverse lookup
111
+
for typeName, modelClass in cls.modelMap.items():
112
+
if isinstance(modelInstance, modelClass):
113
+
modelType = typeName
116
+
if modelType is None:
117
+
raise SerializationError("modelInstance", "Unknown model type")
119
+
# Convert to dict and add type field
120
+
result = modelInstance.model_dump(exclude_unset=True)
121
+
result["type"] = modelType
123
+
# Handle special cases
124
+
if modelType == "record" and "type" in result:
125
+
result["$type"] = result.pop("type")
128
+
except Exception as e:
129
+
raise SerializationError("toLexicon", f"Failed to serialize model: {e}")
132
+
def validateLexicon(cls, lexiconJson: Union[str, Dict[str, Any]]) -> bool:
134
+
Validate Lexicon JSON against schema definitions.
137
+
lexiconJson: Lexicon JSON to validate
140
+
True if valid, False otherwise
143
+
cls.fromLexicon(lexiconJson)
145
+
except (ValidationError, SerializationError):