change data model design for a better JSON schema

This commit is contained in:
Sina Atalay 2023-11-03 20:52:14 +01:00
parent e176f1bf36
commit 3070092a2b
2 changed files with 309 additions and 61 deletions

View File

@ -323,7 +323,7 @@ def generate_json_schema(output_directory: str) -> str:
# ======================================================================================
# CUSTOM DATA TYPES ====================================================================
# DESIGN MODELS ========================================================================
# ======================================================================================
# To understand how to create custom data types, see:
@ -337,14 +337,6 @@ LaTeXDimension = Annotated[
LaTeXString = Annotated[str, AfterValidator(escape_latex_characters)]
SpellCheckedString = Annotated[LaTeXString, AfterValidator(check_spelling)]
# ======================================================================================
# ======================================================================================
# ======================================================================================
# ======================================================================================
# DESIGN MODELS ========================================================================
# ======================================================================================
class ClassicThemePageMargins(BaseModel):
"""This class stores the margins of pages for the classic theme."""
@ -1034,24 +1026,20 @@ class Connection(BaseModel):
return url
class Section(BaseModel):
"""This class stores a section information."""
class SectionBase(BaseModel):
"""This class stores a section information.
It is the parent class of all the section classes like
`#!python SectionWithEducationEntries`, `#!python SectionWithExperienceEntries`,
`#!python SectionWithNormalEntries`, `#!python SectionWithOneLineEntries`, and
`#!python SectionWithPublicationEntries`.
"""
title: LaTeXString = Field(
title="Section Title",
description="The title of the section.",
examples=["My Custom Section"],
)
entry_type: Literal[
"OneLineEntry",
"NormalEntry",
"ExperienceEntry",
"EducationEntry",
"PublicationEntry",
] = Field(
title="Entry Type",
description="The type of the entries in the section.",
)
link_text: Optional[LaTeXString] = Field(
default=None,
title="Link Text",
@ -1062,12 +1050,6 @@ class Section(BaseModel):
),
examples=["view on GitHub", "view on LinkedIn"],
)
entries: list[
OneLineEntry | NormalEntry | ExperienceEntry | EducationEntry | PublicationEntry
] = Field(
title="Entries",
description="The entries of the section. The format depends on the entry type.",
)
@field_validator("title")
@classmethod
@ -1076,6 +1058,73 @@ class Section(BaseModel):
return title.title()
entry_type_field = Field(
title="Entry Type",
description="The type of the entries in the section.",
)
entries_field = Field(
title="Entries",
description="The entries of the section. The format depends on the entry type.",
)
class SectionWithEducationEntries(SectionBase):
"""This class stores a section with
[EducationEntry](../user_guide.md#educationentry)s.
"""
entry_type: Literal["EducationEntry"] = entry_type_field
entries: list[EducationEntry] = entries_field
class SectionWithExperienceEntries(SectionBase):
"""This class stores a section with
[ExperienceEntry](../user_guide.md#experienceentry)s.
"""
entry_type: Literal["ExperienceEntry"] = entry_type_field
entries: list[ExperienceEntry] = entries_field
class SectionWithNormalEntries(SectionBase):
"""This class stores a section with
[NormalEntry](../user_guide.md#normalentry)s.
"""
entry_type: Literal["NormalEntry"] = entry_type_field
entries: list[NormalEntry] = entries_field
class SectionWithOneLineEntries(SectionBase):
"""This class stores a section with
[OneLineEntry](../user_guide.md#onelineentry)s.
"""
entry_type: Literal["OneLineEntry"] = entry_type_field
entries: list[OneLineEntry] = entries_field
class SectionWithPublicationEntries(SectionBase):
"""This class stores a section with
[PublicationEntry](../user_guide.md#publicationentry)s.
"""
entry_type: Literal["PublicationEntry"] = entry_type_field
entries: list[PublicationEntry] = entries_field
Section = Annotated[
SectionWithEducationEntries
| SectionWithExperienceEntries
| SectionWithNormalEntries
| SectionWithOneLineEntries
| SectionWithPublicationEntries,
Field(
discriminator="entry_type",
),
]
class CurriculumVitae(BaseModel):
"""This class bindes all the information of a CV together."""
@ -1284,7 +1333,7 @@ class CurriculumVitae(BaseModel):
@computed_field
@cached_property
def sections(self) -> list[Section]:
def sections(self) -> list[SectionBase]:
sections = []
# Pre-defined sections (i.e. sections that are not custom)):
@ -1368,7 +1417,15 @@ class CurriculumVitae(BaseModel):
" order 😷"
)
section = Section(
object_map = {
"EducationEntry": SectionWithEducationEntries,
"ExperienceEntry": SectionWithExperienceEntries,
"NormalEntry": SectionWithNormalEntries,
"OneLineEntry": SectionWithOneLineEntries,
"PublicationEntry": SectionWithPublicationEntries,
}
section = object_map[entry_type](
title=section_name,
entry_type=entry_type, # type: ignore
entries=entries,

View File

@ -534,7 +534,33 @@
"allOf": [
{
"items": {
"$ref": "#/$defs/Section"
"discriminator": {
"mapping": {
"EducationEntry": "#/$defs/SectionWithEducationEntries",
"ExperienceEntry": "#/$defs/SectionWithExperienceEntries",
"NormalEntry": "#/$defs/SectionWithNormalEntries",
"OneLineEntry": "#/$defs/SectionWithOneLineEntries",
"PublicationEntry": "#/$defs/SectionWithPublicationEntries"
},
"propertyName": "entry_type"
},
"oneOf": [
{
"$ref": "#/$defs/SectionWithEducationEntries"
},
{
"$ref": "#/$defs/SectionWithExperienceEntries"
},
{
"$ref": "#/$defs/SectionWithNormalEntries"
},
{
"$ref": "#/$defs/SectionWithOneLineEntries"
},
{
"$ref": "#/$defs/SectionWithPublicationEntries"
}
]
},
"type": "array"
}
@ -1263,7 +1289,7 @@
"type": "object",
"additionalProperties": false
},
"Section": {
"SectionWithEducationEntries": {
"properties": {
"title": {
"description": "The title of the section.",
@ -1273,18 +1299,6 @@
"title": "Section Title",
"type": "string"
},
"entry_type": {
"description": "The type of the entries in the section.",
"enum": [
"OneLineEntry",
"NormalEntry",
"ExperienceEntry",
"EducationEntry",
"PublicationEntry"
],
"title": "Entry Type",
"type": "string"
},
"link_text": {
"default": null,
"description": "If the section has a link, then what should be the text of the link? If this field is not provided, then the link text will be generated automatically based on the URL.",
@ -1299,26 +1313,15 @@
}
]
},
"entry_type": {
"const": "EducationEntry",
"description": "The type of the entries in the section.",
"title": "Entry Type"
},
"entries": {
"description": "The entries of the section. The format depends on the entry type.",
"items": {
"oneOf": [
{
"$ref": "#/$defs/OneLineEntry"
},
{
"$ref": "#/$defs/NormalEntry"
},
{
"$ref": "#/$defs/ExperienceEntry"
},
{
"$ref": "#/$defs/EducationEntry"
},
{
"$ref": "#/$defs/PublicationEntry"
}
]
"$ref": "#/$defs/EducationEntry"
},
"title": "Entries",
"type": "array"
@ -1329,7 +1332,195 @@
"entry_type",
"entries"
],
"title": "Section",
"title": "SectionWithEducationEntries",
"type": "object",
"additionalProperties": false
},
"SectionWithExperienceEntries": {
"properties": {
"title": {
"description": "The title of the section.",
"examples": [
"My Custom Section"
],
"title": "Section Title",
"type": "string"
},
"link_text": {
"default": null,
"description": "If the section has a link, then what should be the text of the link? If this field is not provided, then the link text will be generated automatically based on the URL.",
"examples": [
"view on GitHub",
"view on LinkedIn"
],
"title": "Link Text",
"allOf": [
{
"type": "string"
}
]
},
"entry_type": {
"const": "ExperienceEntry",
"description": "The type of the entries in the section.",
"title": "Entry Type"
},
"entries": {
"description": "The entries of the section. The format depends on the entry type.",
"items": {
"$ref": "#/$defs/ExperienceEntry"
},
"title": "Entries",
"type": "array"
}
},
"required": [
"title",
"entry_type",
"entries"
],
"title": "SectionWithExperienceEntries",
"type": "object",
"additionalProperties": false
},
"SectionWithNormalEntries": {
"properties": {
"title": {
"description": "The title of the section.",
"examples": [
"My Custom Section"
],
"title": "Section Title",
"type": "string"
},
"link_text": {
"default": null,
"description": "If the section has a link, then what should be the text of the link? If this field is not provided, then the link text will be generated automatically based on the URL.",
"examples": [
"view on GitHub",
"view on LinkedIn"
],
"title": "Link Text",
"allOf": [
{
"type": "string"
}
]
},
"entry_type": {
"const": "NormalEntry",
"description": "The type of the entries in the section.",
"title": "Entry Type"
},
"entries": {
"description": "The entries of the section. The format depends on the entry type.",
"items": {
"$ref": "#/$defs/NormalEntry"
},
"title": "Entries",
"type": "array"
}
},
"required": [
"title",
"entry_type",
"entries"
],
"title": "SectionWithNormalEntries",
"type": "object",
"additionalProperties": false
},
"SectionWithOneLineEntries": {
"properties": {
"title": {
"description": "The title of the section.",
"examples": [
"My Custom Section"
],
"title": "Section Title",
"type": "string"
},
"link_text": {
"default": null,
"description": "If the section has a link, then what should be the text of the link? If this field is not provided, then the link text will be generated automatically based on the URL.",
"examples": [
"view on GitHub",
"view on LinkedIn"
],
"title": "Link Text",
"allOf": [
{
"type": "string"
}
]
},
"entry_type": {
"const": "OneLineEntry",
"description": "The type of the entries in the section.",
"title": "Entry Type"
},
"entries": {
"description": "The entries of the section. The format depends on the entry type.",
"items": {
"$ref": "#/$defs/OneLineEntry"
},
"title": "Entries",
"type": "array"
}
},
"required": [
"title",
"entry_type",
"entries"
],
"title": "SectionWithOneLineEntries",
"type": "object",
"additionalProperties": false
},
"SectionWithPublicationEntries": {
"properties": {
"title": {
"description": "The title of the section.",
"examples": [
"My Custom Section"
],
"title": "Section Title",
"type": "string"
},
"link_text": {
"default": null,
"description": "If the section has a link, then what should be the text of the link? If this field is not provided, then the link text will be generated automatically based on the URL.",
"examples": [
"view on GitHub",
"view on LinkedIn"
],
"title": "Link Text",
"allOf": [
{
"type": "string"
}
]
},
"entry_type": {
"const": "PublicationEntry",
"description": "The type of the entries in the section.",
"title": "Entry Type"
},
"entries": {
"description": "The entries of the section. The format depends on the entry type.",
"items": {
"$ref": "#/$defs/PublicationEntry"
},
"title": "Entries",
"type": "array"
}
},
"required": [
"title",
"entry_type",
"entries"
],
"title": "SectionWithPublicationEntries",
"type": "object",
"additionalProperties": false
},