Add ORM models for the pixel grids
- add Grid, Pixel, and AddressPixelAssociation ORM models - each Grid belongs to a City an is characterized by the side_length of all the square Pixels contained in it - Pixels aggregate Addresses => many-to-many relationship (that is modeled with SQLAlchemy's Association Pattern to implement a couple of constraints)
This commit is contained in:
parent
6cb4be80f6
commit
f996376b13
15 changed files with 665 additions and 36 deletions
59
src/urban_meal_delivery/db/pixels.py
Normal file
59
src/urban_meal_delivery/db/pixels.py
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
"""Provide the ORM's `Pixel` model."""
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
|
||||
from urban_meal_delivery.db import meta
|
||||
|
||||
|
||||
class Pixel(meta.Base):
|
||||
"""A pixel in a `Grid`.
|
||||
|
||||
Square pixels aggregate `Address` objects within a `City`.
|
||||
Every `Address` belongs to exactly one `Pixel` in a `Grid`.
|
||||
|
||||
Every `Pixel` has a unique "coordinate" within the `Grid`.
|
||||
"""
|
||||
|
||||
__tablename__ = 'pixels'
|
||||
|
||||
# Columns
|
||||
id = sa.Column(sa.Integer, primary_key=True, autoincrement=True) # noqa:WPS125
|
||||
_grid_id = sa.Column('grid_id', sa.SmallInteger, nullable=False, index=True)
|
||||
n_x = sa.Column(sa.SmallInteger, nullable=False, index=True)
|
||||
n_y = sa.Column(sa.SmallInteger, nullable=False, index=True)
|
||||
|
||||
# Constraints
|
||||
__table_args__ = (
|
||||
sa.ForeignKeyConstraint(
|
||||
['grid_id'], ['grids.id'], onupdate='RESTRICT', ondelete='RESTRICT',
|
||||
),
|
||||
sa.CheckConstraint('0 <= n_x', name='n_x_is_positive'),
|
||||
sa.CheckConstraint('0 <= n_y', name='n_y_is_positive'),
|
||||
# Needed by a `ForeignKeyConstraint` in `AddressPixelAssociation`.
|
||||
sa.UniqueConstraint('id', 'grid_id'),
|
||||
# Each coordinate within the same `grid` is used at most once.
|
||||
sa.UniqueConstraint('grid_id', 'n_x', 'n_y'),
|
||||
)
|
||||
|
||||
# Relationships
|
||||
grid = orm.relationship('Grid', back_populates='pixels')
|
||||
addresses = orm.relationship('AddressPixelAssociation', back_populates='pixel')
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Non-literal text representation."""
|
||||
return '<{cls}: ({x}, {y})>'.format(
|
||||
cls=self.__class__.__name__, x=self.n_x, y=self.n_y,
|
||||
)
|
||||
|
||||
# Convenience properties
|
||||
|
||||
@property
|
||||
def side_length(self) -> int:
|
||||
"""The length of one side of a pixel in meters."""
|
||||
return self.grid.side_length
|
||||
|
||||
@property
|
||||
def area(self) -> float:
|
||||
"""The area of a pixel in square kilometers."""
|
||||
return self.grid.pixel_area
|
||||
Loading…
Add table
Add a link
Reference in a new issue