Skip to content

Commit

Permalink
Improved schema model
Browse files Browse the repository at this point in the history
  • Loading branch information
roll committed Sep 7, 2023
1 parent acf7113 commit 69ae11d
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 43 deletions.
24 changes: 22 additions & 2 deletions dpspecs/models/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
from pydantic import BaseModel
from typing import Any, Dict, List

from pydantic import BaseModel, ValidationError
from pydantic_core import ErrorDetails


class Model(BaseModel):
pass
def __str__(self):
return str(self.to_descriptor())

Check warning on line 9 in dpspecs/models/base.py

View check run for this annotation

Codecov / codecov/patch

dpspecs/models/base.py#L9

Added line #L9 was not covered by tests

@classmethod
def validate_descriptor(cls, descriptor: Dict[str, Any]):
errors: List[ErrorDetails] = []
try:
cls.model_validate(descriptor)
except ValidationError as e:
errors = e.errors()
return errors

Check warning on line 18 in dpspecs/models/base.py

View check run for this annotation

Codecov / codecov/patch

dpspecs/models/base.py#L13-L18

Added lines #L13 - L18 were not covered by tests

@classmethod
def from_descriptor(cls, descriptor: Dict[str, Any]):
return cls(**descriptor)

Check warning on line 22 in dpspecs/models/base.py

View check run for this annotation

Codecov / codecov/patch

dpspecs/models/base.py#L22

Added line #L22 was not covered by tests

def to_descriptor(self):
return self.model_dump(exclude_unset=True, exclude_none=True)

Check warning on line 25 in dpspecs/models/base.py

View check run for this annotation

Codecov / codecov/patch

dpspecs/models/base.py#L25

Added line #L25 was not covered by tests
108 changes: 68 additions & 40 deletions dpspecs/models/schema.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
from __future__ import annotations

from typing import Any, Dict, List, Literal, Optional
from typing import Any, Dict, List, Literal, Optional, Union

import pydantic
from typing_extensions import Annotated

from .base import Model

# Schema


class Schema(Model):
"""Schema model"""

name: Optional[str] = None
type: Optional[str] = None
title: Optional[str] = None
description: Optional[str] = None

fields: List[Field]
"""List of fields"""

Expand All @@ -21,7 +21,10 @@ class Schema(Model):
foreignKeys: Optional[List[ForeignKey]] = None


class Field(Model):
# Fields


class BaseField(Model):
name: str
type: str
title: Optional[str] = None
Expand All @@ -30,80 +33,105 @@ class Field(Model):
missingValues: Optional[List[str]] = None


class AnyField(Field):
type: Literal["any"]
class AnyField(BaseField):
type: Literal["any"] = "any"


class ArrayField(Field):
type: Literal["array"]
class ArrayField(BaseField):
type: Literal["array"] = "array"
# support json/csv format
arrayItem: Optional[Dict[str, Any]] = None


class BooleanField(Field):
type: Literal["boolean"]
class BooleanField(BaseField):
type: Literal["boolean"] = "boolean"
trueValues: Optional[List[str]] = None
falseValues: Optional[List[str]] = None


class DateField(Field):
type: Literal["date"]
class DateField(BaseField):
type: Literal["date"] = "date"


class DatetimeField(Field):
type: Literal["datetime"]
class DatetimeField(BaseField):
type: Literal["datetime"] = "datetime"


class DurationField(Field):
type: Literal["duration"]
class DurationField(BaseField):
type: Literal["duration"] = "duration"


class GeojsonField(Field):
type: Literal["geojson"]
class GeojsonField(BaseField):
type: Literal["geojson"] = "geojson"


class GeopointField(Field):
type: Literal["geopoint"]
class GeopointField(BaseField):
type: Literal["geopoint"] = "geopoint"


class IntegerField(Field):
type: Literal["integer"]
class IntegerField(BaseField):
type: Literal["integer"] = "integer"
bareNumber: Optional[bool] = None
groupChar: Optional[str] = None


class NumberField(Field):
type: Literal["number"]
class NumberField(BaseField):
type: Literal["number"] = "number"
bareNumber: Optional[bool] = None
groupChar: Optional[str] = None
decimalChar: Optional[str] = None


class ObjectField(Field):
type: Literal["object"]
class ObjectField(BaseField):
type: Literal["object"] = "object"


class StringField(Field):
type: Literal["string"]
class StringField(BaseField):
type: Literal["string"] = "string"


class TimeField(Field):
type: Literal["time"]
class TimeField(BaseField):
type: Literal["time"] = "time"


class YearField(Field):
type: Literal["year"]
class YearField(BaseField):
type: Literal["year"] = "year"


class YearmonthField(Field):
type: Literal["yearmonth"]
class YearmonthField(BaseField):
type: Literal["yearmonth"] = "yearmonth"


class ForeignKeyReference(Model):
fields: List[str]
resource: str
Field = Annotated[
Union[
AnyField,
ArrayField,
BooleanField,
DateField,
DatetimeField,
DurationField,
GeojsonField,
GeopointField,
IntegerField,
NumberField,
ObjectField,
StringField,
TimeField,
YearField,
YearmonthField,
],
pydantic.Field(discriminator="type"),
]


# Foreign keys


class ForeignKey(Model):
fields: List[str]
reference: Optional[ForeignKeyReference] = None


class ForeignKeyReference(Model):
fields: List[str]
resource: str
2 changes: 1 addition & 1 deletion mkdocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ theme:
# - navigation.instant
# - navigation.prune
- navigation.sections
# - navigation.tabs
- navigation.tabs
# - navigation.tabs.sticky
- navigation.top
- navigation.tracking
Expand Down

0 comments on commit 69ae11d

Please sign in to comment.