diff --git a/alembic/env.py b/alembic/env.py index 7966288..c8174a7 100644 --- a/alembic/env.py +++ b/alembic/env.py @@ -5,7 +5,7 @@ from sqlalchemy import pool from alembic import context from sqlmodel import SQLModel -from etl.transform.preSiteNoteTypes import * +from etl.load.preSiteNoteTypes import * import os diff --git a/etl/load/preSiteNoteTypes.py b/etl/load/preSiteNoteTypes.py new file mode 100644 index 0000000..5ce4314 --- /dev/null +++ b/etl/load/preSiteNoteTypes.py @@ -0,0 +1,234 @@ +from sqlmodel import Field, SQLModel, Relationship +import uuid +from typing import Optional, List +from datetime import datetime +from pydantic import EmailStr +from sqlalchemy import Column +from sqlalchemy.dialects.postgresql import UUID + + +class BaseModel(SQLModel): + id: uuid.UUID = Field( + default_factory=uuid.uuid4, + sa_column=Column(UUID(as_uuid=True), primary_key=True) + ) + + +class Dimension(BaseModel, table=True): + floor_area_m2: float + room_height_m: float + loss_perimeter_m: float + party_wall_length_m: float + property_detail_id: Optional[uuid.UUID] = Field(default=None, foreign_key="propertydetail.id") + + +class Walls(BaseModel, table=True): + construction: str + insulation: str + insulation_thickness_mm: str + wall_thickness_measured: bool + wall_thickness_mm: Optional[int] + u_value_known: bool + u_value_w_m2_k: Optional[float] + dry_lining: bool + alternative_wall_present: bool + + +class Roofs(BaseModel, table=True): + construction: str + insulation_type: str + insulation_thickness: str + u_value_known: bool + + +class Floors(BaseModel, table=True): + floor_type: str + ground_floor_construction: str + ground_floor_insulation_type: Optional[str] = "" + floor_insulation_thickness_mm: Optional[float] = -1 + u_value_known: bool + + +class Windows(BaseModel, table=True): + glazing_type: str + area_m2: float + roof_window: bool + orientation: str + u_value_w_m2_k: int + g_value: int + property_detail_id: Optional[uuid.UUID] = Field(default=None, foreign_key="propertydetail.id") + + +class PropertyDetail(BaseModel, table=True): + age_band: str + wall_id: Optional[uuid.UUID] = Field(default=None, foreign_key="walls.id") + roof_id: Optional[uuid.UUID] = Field(default=None, foreign_key="roofs.id") + floor_id: Optional[uuid.UUID] = Field(default=None, foreign_key="floors.id") + + dimensions: List[Dimension] = Relationship(back_populates="property_detail") + windows: List[Windows] = Relationship(back_populates="property_detail") + + +Dimension.property_detail = Relationship(back_populates="dimensions") +Windows.property_detail = Relationship(back_populates="windows") + + +class Door(BaseModel, table=True): + no_of_doors: int + no_of_insulated_doors: int + u_value_w_m2_k: Optional[str] + + +class VentilationAndCooling(BaseModel, table=True): + no_of_open_fireplaces: int + ventilation_type: str + space_cooling_system_present: bool + + +class Lighting(BaseModel, table=True): + total_no_of_light_fittings: int + total_no_of_lel_fittings: int + + +class HeatingSystemControls(BaseModel, table=True): + control_type: str + flue_type: str + fan_assisted_flue: bool + heat_emitter_type: str + electricity_meter_type: Optional[str] = "" + mains_gas_available: Optional[bool] = False + + +class Heating(BaseModel, table=True): + type: str + heating_source: str + efficiency_source: str + heating_fuel: str + brand_name: str + model_name: str + model_qualifer: str + sap_2009_table: Optional[str] = "" + percentage_of_heated_floor_area_served: Optional[str] = "" + controls_id: Optional[uuid.UUID] = Field(default=None, foreign_key="heatingsystemcontrols.id") + + +class HeatingType(BaseModel, table=True): + heating_type: str + fuel_type: str + + +class WaterHeating(BaseModel, table=True): + heating_type: str + fuel_type: str + + +class HotWaterCylinder(BaseModel, table=True): + volume: str + insulation_type: str + insulation_thickness: str + thermostat: bool + + +class SolarWaterHeating(BaseModel, table=True): + solar_water_heating_details_known: bool + + +class ShowerAndBaths(BaseModel, table=True): + no_of_rooms_with_baths_and_or_shower: int + no_of_rooms_with_mixer_shower_and_no_baths: int + no_of_rooms_with_mixer_shower_and_baths: int + + +class FlueGasHeatRecoverySystem(BaseModel, table=True): + fghrs_present: bool + + +class PhotovoltaicPanel(BaseModel, table=True): + pvs_are_connected_to_dwelling_electricity_meter: bool + percentage_of_external_roof_area_with_pvs: str + + +class WindTurbine(BaseModel, table=True): + wind_turbine: bool + + +class OtherDetails(BaseModel, table=True): + electricity_meter_type: str + main_gas_avalible: bool + + +class PropertyDescription(BaseModel, table=True): + built_form: str + detachment_or_position: str + no_of_main_property: int + no_of_extension_1: Optional[int] = 0 + no_of_extension_2: Optional[int] = 0 + no_of_extension_3: Optional[int] = 0 + no_of_extension_4: Optional[int] = 0 + no_of_habitable_rooms: int + no_of_heated_rooms: int + heated_basement: bool + conservatory_type: str + percentage_of_draught_proofed: int + terrain_type: str + conservatory: bool + + main_property_id: uuid.UUID = Field(foreign_key="propertydetail.id") + ex1_property_id: Optional[uuid.UUID] = Field(default=None, foreign_key="propertydetail.id") + ex2_property_id: Optional[uuid.UUID] = Field(default=None, foreign_key="propertydetail.id") + ex3_property_id: Optional[uuid.UUID] = Field(default=None, foreign_key="propertydetail.id") + ex4_property_id: Optional[uuid.UUID] = Field(default=None, foreign_key="propertydetail.id") + + door_id: Optional[uuid.UUID] = Field(default=None, foreign_key="door.id") + ventilation_and_cooling_id: Optional[uuid.UUID] = Field(default=None, foreign_key="ventilationandcooling.id") + lighting_id: Optional[uuid.UUID] = Field(default=None, foreign_key="lighting.id") + water_heating_id: Optional[uuid.UUID] = Field(default=None, foreign_key="waterheating.id") + hot_water_cylinder_id: Optional[uuid.UUID] = Field(default=None, foreign_key="hotwatercylinder.id") + solar_water_heating_id: Optional[uuid.UUID] = Field(default=None, foreign_key="solarwaterheating.id") + shower_and_baths_id: Optional[uuid.UUID] = Field(default=None, foreign_key="showerandbaths.id") + flue_gas_heat_recovery_system_id: Optional[uuid.UUID] = Field(default=None, foreign_key="fluegasheatrecoverysystem.id") + photovoltaic_panel_id: Optional[uuid.UUID] = Field(default=None, foreign_key="photovoltaicpanel.id") + wind_turbine_id: Optional[uuid.UUID] = Field(default=None, foreign_key="windturbine.id") + other_details_id: Optional[uuid.UUID] = Field(default=None, foreign_key="otherdetails.id") + main_heating_id: Optional[uuid.UUID] = Field(default=None, foreign_key="heating.id") + main_heating2_id: Optional[uuid.UUID] = Field(default=None, foreign_key="heating.id") + secondary_heating_type_id: Optional[uuid.UUID] = Field(default=None, foreign_key="heatingtype.id") + + +class AssessorInfo(BaseModel, table=True): + accreditation_number: str + name: str + phone_number: Optional[str] = None + email_address: Optional[EmailStr] = None + + +class SurverySummaryInfo(BaseModel, table=True): + reference_number: str + epc_language: str + uprn: Optional[str] = "" + postcode: str + region: str + address: str + town: str + county: Optional[str] = "" + property_tenure: str + transaction_type: str + inspection_date: datetime + current_sap: str + potential_sap: str + current_ei: str + potential_ei: str + current_annual_emissions: str + current_annual_emission_including_0925_multiplayer: str + current_annual_energy_costs: str + + +class CompanyInfo(BaseModel, table=True): + trading_name: str + post_code: str + fax_number: Optional[str] = None + related_party_disclosure: Optional[str] = None + + +class Insulation(BaseModel, table=True): + type: str diff --git a/etl/transform/preSiteNoteTypes.py b/etl/transform/preSiteNoteTypes.py index f77a2d7..7e25682 100644 --- a/etl/transform/preSiteNoteTypes.py +++ b/etl/transform/preSiteNoteTypes.py @@ -1,31 +1,28 @@ -from sqlmodel import Field, SQLModel, Relationship +from sqlmodel import Field, SQLModel import uuid from datetime import datetime from pydantic import field_validator, EmailStr from typing import Optional, List from sqlalchemy import Column -from sqlalchemy.orm import relationship from sqlalchemy.dialects.postgresql import UUID class BaseModel(SQLModel): id: uuid.UUID = Field( default_factory=uuid.uuid4, - primary_key=True, + sa_column=Column(UUID(as_uuid=True), primary_key=True) ) -class Dimension(BaseModel, table=True): +class Dimension(BaseModel): floor_area_m2: float room_height_m: float loss_perimeter_m: float party_wall_length_m: float -class CompanyInfo(BaseModel, table=True): +class CompanyInfo(BaseModel): trading_name: str post_code: str fax_number: Optional[str] = None related_party_disclosure: Optional[str] = None - - __table_args__ = {"extend_existing": True} @field_validator('related_party_disclosure') def set_none_if_none_of_the_above(cls, v): @@ -33,7 +30,7 @@ class CompanyInfo(BaseModel, table=True): return None return v -class PreSiteNotesSummaryInfo(BaseModel, table=True): +class SurverySummaryInfo(BaseModel): reference_number: str epc_language: str uprn: Optional[str] = "" @@ -52,14 +49,8 @@ class PreSiteNotesSummaryInfo(BaseModel, table=True): current_annual_emissions: str current_annual_emission_including_0925_multiplayer: str current_annual_energy_costs: str - - pre_site_note: Optional["PreSiteNote"] = Relationship( - back_populates="summary_info", - sa_relationship=relationship("PreSiteNote", back_populates="summary_info", uselist=False) - ) - -class Walls(BaseModel, table=True): +class Walls(BaseModel): construction: str insulation: str insulation_thickness_mm: str @@ -70,20 +61,20 @@ class Walls(BaseModel, table=True): dry_lining: bool alternative_wall_present: bool -class Roofs(BaseModel, table=True): +class Roofs(BaseModel): construction: str insulation_type: str insulation_thickness: str u_value_known: bool -class Floors(BaseModel, table=True): +class Floors(BaseModel): floor_type: str ground_floor_construction: str ground_floor_insulation_type: Optional[str] = "" floor_insulation_thickness_mm: Optional[float] = -1 u_value_known: bool -class Door(BaseModel, table=True): +class Door(BaseModel): no_of_doors: int no_of_insulated_doors: int u_value_w_m2_k: Optional[str] @@ -93,23 +84,17 @@ class AssessorInfo(BaseModel, table=True): name: str phone_number: Optional[str] = None email_address: Optional[EmailStr] = None - company_id: Optional[uuid.UUID] = Field( - foreign_key="companyinfo.id", # Referencing CompanyInfo - nullable=False - ) - - pre_site_notes: List["PreSiteNote"] = Relationship(back_populates="assessor") -class VentilationAndCooling(BaseModel, table=True): +class VentilationAndCooling(BaseModel): no_of_open_fireplaces: int ventilation_type: str space_cooling_system_present: bool -class Lighting(BaseModel, table=True): +class Lighting(BaseModel): total_no_of_light_fittings: int total_no_of_lel_fittings: int -class HeatingSystemControls(BaseModel, table=True): +class HeatingSystemControls(BaseModel): control_type: str flue_type: str fan_assisted_flue: bool @@ -117,11 +102,7 @@ class HeatingSystemControls(BaseModel, table=True): electricity_meter_type: Optional[str] = "" mains_gas_available: Optional[bool] = False - # Reverse relationship (optional) - heating: Optional["Heating"] = Relationship( - back_populates="controls", - ) -class Heating(BaseModel, table=True): +class Heating(BaseModel): type: str heating_source: str efficiency_source: str @@ -131,48 +112,45 @@ class Heating(BaseModel, table=True): model_qualifer: str sap_2009_table: Optional[str] = "" percentage_of_heated_floor_area_served: Optional[str] = "" + controls: HeatingSystemControls - # Foregin Key to HeatingSystemControls - controls_id: Optional[uuid.UUID] = Field(foreign_key="heatingsystemcontrols.id") - controls: Optional["HeatingSystemControls"] = Relationship(back_populates="heating") - -class HeatingType(BaseModel, table=True): +class HeatingType(BaseModel): heating_type: str fuel_type: str -class WaterHeating(BaseModel, table=True): +class WaterHeating(BaseModel): heating_type: str fuel_type: str -class HotWaterCylinder(BaseModel, table=True): +class HotWaterCylinder(BaseModel): volume: str insulation_type: str insulation_thickness: str thermostat: bool -class SolarWaterHeating(BaseModel, table=True): +class SolarWaterHeating(BaseModel): solar_water_heating_details_known: bool -class ShowerAndBaths(BaseModel, table=True): +class ShowerAndBaths(BaseModel): no_of_rooms_with_baths_and_or_shower: int no_of_rooms_with_mixer_shower_and_no_baths: int no_of_rooms_with_mixer_shower_and_baths: int -class FlueGasHeatRecoverySystem(BaseModel, table=True): +class FlueGasHeatRecoverySystem(BaseModel): fghrs_present: bool -class PhotovoltaicPanel(BaseModel, table=True): +class PhotovoltaicPanel(BaseModel): pvs_are_connected_to_dwelling_electricity_meter: bool percentage_of_external_roof_area_with_pvs: str -class WindTurbine(BaseModel, table=True): +class WindTurbine(BaseModel): wind_turbine: bool -class OtherDetails(BaseModel, table=True): +class OtherDetails(BaseModel): electricity_meter_type: str main_gas_avalible: bool -class Windows(BaseModel, table=True): +class Windows(BaseModel): glazing_type: str area_m2: float roof_window: bool @@ -180,42 +158,20 @@ class Windows(BaseModel, table=True): u_value_w_m2_k: int g_value: int - property_db: Optional["PropertyDetail"] = Relationship(back_populates="windows_db") - - -class PropertyDetail(BaseModel, table=True): +class PropertyDetail(BaseModel): # change this name to build parts age_band: str - windows: Optional[List[Windows]] = [] - windows_db: List[Windows] = Relationship(back_populates="property_db") - - wall: Optional[Walls] = None - wall_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="walls.id" - ) - roof: Optional[Roofs] = None - roof_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="roofs.id" - ) - floor: Optional[Floors] = None - floor_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="floors.id" - ) dimensions: List[Dimension] = [] - dimensions_id: Optional[List[uuid.UUID]] = Field( - default=None, - foreign_key="dimensions.id" - ) + wall: Optional[Walls] = None + roof: Optional[Roofs] = None + floor: Optional[Floors] = None + windows: Optional[List[Windows]] = [] class PropertyDescription(BaseModel): built_form: str detachment_or_position: str no_of_main_property: int - conservatory: bool no_of_extension_1: Optional[int] = 0 no_of_extension_2: Optional[int] = 0 no_of_extension_3: Optional[int] = 0 @@ -227,130 +183,31 @@ class PropertyDescription(BaseModel): percentage_of_draught_proofed: int terrain_type: str main_property: PropertyDetail - - ex1_property: Optional[PropertyDetail] = None ex2_property: Optional[PropertyDetail] = None ex3_property: Optional[PropertyDetail] = None ex4_property: Optional[PropertyDetail] = None - # Do walls next, check if variable is real similar to main heating - - # Door - door_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="door.id" - ) + conservatory: bool door: Optional[Door] - - - # ventilation and cooling - vetilation_and_cooling_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="ventilationandcooling.id" - ) ventilationAndCooling: Optional[VentilationAndCooling] - - - # lighting - lighting_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="lighting.id" - ) lighting: Optional[Lighting] - - - # water heating - water_heating_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="waterheating.id" - ) waterHeating: Optional[WaterHeating] - - - #hotwatercylinder - hot_water_cylinder_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="hotwatercylinder.id" - ) hotWaterCylinder: Optional[HotWaterCylinder] - - #solarAndWaterHeating - solar_water_heating_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="solarwaterheating.id" - ) solarWaterHeating: Optional[SolarWaterHeating] - - # shower and baths - shower_and_baths_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="showerandbaths.id" - ) showerAndBaths: Optional[ShowerAndBaths] - - # flueGasHeatRecoverySystem - flue_gas_heat_recovery_system_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="fluegasheatrecoverysystem.id" - ) flueGasHeatRecoverySystem: Optional[FlueGasHeatRecoverySystem] - - # photovolaticPanel - photo_voltaic_panel_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key='photovoltaicpanel.id' - ) photovoltaicPanel: Optional[PhotovoltaicPanel] - - # windTuribe - wind_turbine_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="windturbine.id" - ) windTurbine: Optional[WindTurbine] - - - # other details - other_details_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="otherdetails.id" - ) - otherDetails: Optional["OtherDetails"] - + otherDetails: Optional[OtherDetails] mainHeating: Optional[Heating] - - # Foreign key to Main Heating 2 - main_heating_2_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="heatingtype.id" - ) mainHeating2: Optional[Heating] - - # Foreign key to HeatingType - secondary_heating_type_id: Optional[uuid.UUID] = Field( - default=None, - foreign_key="heatingtype.id" - ) secondaryHeatingType: Optional[HeatingType] +# class PropertyReport(): + # TODO: Property description + # TODO: Due consideration foregin key + # TODO: Which company did it (Osmosis, Warmfront etc) + # TODO: Links to more foreign keys per report etc + class Insulation(BaseModel): - type: str - -# One class to rule them all -class PreSiteNote(BaseModel, table=True): - # Summary Info - summary_info_id: uuid.UUID = Field( - foreign_key="presitenotessummaryinfo.id", - nullable=False - ) - - summary_info: Optional["PreSiteNotesSummaryInfo"] = Relationship(back_populates="pre_site_note") - - - # Assessor Info - assessor_id: uuid.UUID = Field( - foreign_key="assessorinfo.id", - nullable=False - ) - - assessor: Optional["AssessorInfo"] = Relationship(back_populates="pre_site_notes") \ No newline at end of file + type: str \ No newline at end of file