Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions schemas/aquifer_system.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from typing import List

from pydantic import BaseModel

from core.enums import GeographicScale, AquiferType
from schemas import BaseResponseModel
from schemas.validators import GeometryMixin
from core.enums import AquiferType, GeographicScale # Import specific Enums


# ------ CREATE ----------
class CreateAquiferSystem(BaseModel):
class CreateAquiferSystem(BaseModel, GeometryMixin):
"""
Schema for creating an aquifer system.
Used during data transfer and API creation.
Expand All @@ -16,8 +16,8 @@ class CreateAquiferSystem(BaseModel):
name: str
description: str | None = None
primary_aquifer_type: AquiferType
geographic_scale: GeographicScale | None = None # e.g., "Regional", "Local", etc.
boundary: str | None = None
geographic_scale: GeographicScale | None = None
# boundary field inherited from GeometryMixin


# ------ RESPONSE ----------
Expand Down
30 changes: 27 additions & 3 deletions schemas/geologic_formation.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,46 @@
from typing import List

from pydantic import BaseModel
from pydantic import BaseModel, field_validator, Field

from schemas import BaseResponseModel
from schemas.validators import DepthIntervalMixin, GeometryMixin
from core.enums import FormationCode, Lithology


# ------ CREATE ----------
class CreateGeologicFormation(BaseModel):
class CreateGeologicFormation(BaseModel, GeometryMixin):
"""
Schema for creating a geologic formation.
Used during data transfer and API creation.
"""

# formation_code has its own custom uppercase validator
formation_code: FormationCode | None = None
description: str | None = None
lithology: Lithology | None = None
boundary: str | None = None
# boundary: inherited from GeometryMixin

@field_validator("formation_code", mode="before")
@classmethod
def upper_case_code(cls, v: str | None) -> str | None:
"""
Automatically uppercase the formation code.
"""
if isinstance(v, str):
return v.upper()
return v


class CreateThingGeologicFormationAssociation(BaseModel, DepthIntervalMixin):
"""
Schema for linking a Thing (Well) to a GeologicFormation.
Uses DepthIntervalMixin to enforce bottom_depth > top_depth.
"""

thing_id: int
geologic_formation_id: int
top_depth: float = Field(ge=0)
bottom_depth: float = Field(ge=0)


# ------ RESPONSE ----------
Expand Down
43 changes: 43 additions & 0 deletions schemas/validators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""
schemas/validators.py
Reusable Pydantic validators and mixins for aquifer and geology related schemas.
May consider expansion for other domain models in the future.
"""

from pydantic import model_validator, field_validator, BaseModel, ValueError, Field
from services.validation.geospatial import validate_wkt_geometry


class DepthIntervalMixin(BaseModel):
Comment thread
ksmuczynski marked this conversation as resolved.
"""
Mixin to enforce:
1. Depths are non-negative (via Field constraints).
2. Bottom depth > top depth (via model_validator).
Assumes the model has 'top_depth' and 'bottom_depth' fields.
"""

top_depth: float = Field(ge=0)
bottom_depth: float = Field(ge=0)

@model_validator(mode="after")
def check_depth_logical_order(self) -> "DepthIntervalMixin":
if self.bottom_depth <= self.top_depth:
raise ValueError(
f"Bottom depth ({self.bottom_depth}) must be greater "
f"than top depth ({self.top_depth})"
)
return self


class GeometryMixin(BaseModel):
"""
Mixin to validate WKT strings for boundary fields.
Delegates logic to the validate_wkt_geometry service function.
"""

boundary: str | None = None

@field_validator("boundary")
@classmethod
def validate_wkt(cls, v: str | None) -> str | None:
return validate_wkt_geometry(v)
Loading